| @@ -23,7 +23,7 @@ | |||||
| from __future__ import unicode_literals | from __future__ import unicode_literals | ||||
| from . import Node | from . import Node | ||||
| from ..compat import htmlentities, str | |||||
| from ..compat import htmlentities, py3k, str | |||||
| __all__ = ["HTMLEntity"] | __all__ = ["HTMLEntity"] | ||||
| @@ -63,28 +63,31 @@ class HTMLEntity(Node): | |||||
| return self.normalize() | return self.normalize() | ||||
| return self | return self | ||||
| def _unichr(self, value): | |||||
| """Implement the builtin unichr() with support for non-BMP code points. | |||||
| if not py3k: | |||||
| @staticmethod | |||||
| def _unichr(value): | |||||
| """Implement builtin unichr() with support for non-BMP code points. | |||||
| On wide Python builds, this functions like the normal unichr(). On | |||||
| narrow builds, this returns the value's corresponding surrogate pair. | |||||
| """ | |||||
| try: | |||||
| return unichr(value) | |||||
| except ValueError: | |||||
| # Test whether we're on the wide or narrow Python build. Check the | |||||
| # length of a non-BMP code point (U+1F64A, SPEAK-NO-EVIL MONKEY): | |||||
| if len("\U0001F64A") == 2: | |||||
| # Ensure this is within the range we can encode: | |||||
| if value > 0x10FFFF: | |||||
| raise ValueError("unichr() arg not in range(0x110000)") | |||||
| code = value - 0x10000 | |||||
| if value < 0: # Invalid code point | |||||
| raise | |||||
| lead = 0xD800 + (code >> 10) | |||||
| trail = 0xDC00 + (code % (1 << 10)) | |||||
| return unichr(lead) + unichr(trail) | |||||
| raise | |||||
| On wide Python builds, this functions like the normal unichr(). On | |||||
| narrow builds, this returns the value's encoded surrogate pair. | |||||
| """ | |||||
| try: | |||||
| return unichr(value) | |||||
| except ValueError: | |||||
| # Test whether we're on the wide or narrow Python build. Check | |||||
| # the length of a non-BMP code point | |||||
| # (U+1F64A, SPEAK-NO-EVIL MONKEY): | |||||
| if len("\U0001F64A") == 2: | |||||
| # Ensure this is within the range we can encode: | |||||
| if value > 0x10FFFF: | |||||
| raise ValueError("unichr() arg not in range(0x110000)") | |||||
| code = value - 0x10000 | |||||
| if value < 0: # Invalid code point | |||||
| raise | |||||
| lead = 0xD800 + (code >> 10) | |||||
| trail = 0xDC00 + (code % (1 << 10)) | |||||
| return unichr(lead) + unichr(trail) | |||||
| raise | |||||
| @property | @property | ||||
| def value(self): | def value(self): | ||||
| @@ -119,19 +122,47 @@ class HTMLEntity(Node): | |||||
| @value.setter | @value.setter | ||||
| def value(self, newval): | def value(self, newval): | ||||
| newval = str(newval) | newval = str(newval) | ||||
| if newval not in htmlentities.entitydefs: | |||||
| test = int(self.value, 16) | |||||
| if test < 0 or (test > 0x10FFFF and int(self.value) > 0x10FFFF): | |||||
| raise ValueError(newval) | |||||
| try: | |||||
| int(newval) | |||||
| except ValueError: | |||||
| try: | |||||
| int(newval, 16) | |||||
| except ValueError: | |||||
| if newval not in htmlentities.entitydefs: | |||||
| raise ValueError("entity value is not a valid name") | |||||
| self._named = True | |||||
| self._hexadecimal = False | |||||
| else: | |||||
| if int(newval, 16) < 0 or int(newval, 16) > 0x10FFFF: | |||||
| raise ValueError("entity value is not in range(0x110000)") | |||||
| self._named = False | |||||
| self._hexadecimal = True | |||||
| else: | |||||
| test = int(newval, 16 if self.hexadecimal else 10) | |||||
| if test < 0 or test > 0x10FFFF: | |||||
| raise ValueError("entity value is not in range(0x110000)") | |||||
| self._named = False | |||||
| self._value = newval | self._value = newval | ||||
| @named.setter | @named.setter | ||||
| def named(self, newval): | def named(self, newval): | ||||
| self._named = bool(newval) | |||||
| newval = bool(newval) | |||||
| if newval and self.value not in htmlentities.entitydefs: | |||||
| raise ValueError("entity value is not a valid name") | |||||
| if not newval: | |||||
| try: | |||||
| int(self.value, 16) | |||||
| except ValueError: | |||||
| err = "current entity value is not a valid Unicode codepoint" | |||||
| raise ValueError(err) | |||||
| self._named = newval | |||||
| @hexadecimal.setter | @hexadecimal.setter | ||||
| def hexadecimal(self, newval): | def hexadecimal(self, newval): | ||||
| self._hexadecimal = bool(newval) | |||||
| newval = bool(newval) | |||||
| if newval and self.named: | |||||
| raise ValueError("a named entity cannot be hexadecimal") | |||||
| self._hexadecimal = newval | |||||
| @hex_char.setter | @hex_char.setter | ||||
| def hex_char(self, newval): | def hex_char(self, newval): | ||||
| @@ -142,8 +173,9 @@ class HTMLEntity(Node): | |||||
| def normalize(self): | def normalize(self): | ||||
| """Return the unicode character represented by the HTML entity.""" | """Return the unicode character represented by the HTML entity.""" | ||||
| chrfunc = chr if py3k else HTMLEntity._unichr | |||||
| if self.named: | if self.named: | ||||
| return unichr(htmlentities.name2codepoint[self.value]) | |||||
| return chrfunc(htmlentities.name2codepoint[self.value]) | |||||
| if self.hexadecimal: | if self.hexadecimal: | ||||
| return self._unichr(int(self.value, 16)) | |||||
| return self._unichr(int(self.value)) | |||||
| return chrfunc(int(self.value, 16)) | |||||
| return chrfunc(int(self.value)) | |||||
| @@ -81,7 +81,7 @@ class Template(Node): | |||||
| in parameter names or values so they are not mistaken for new | in parameter names or values so they are not mistaken for new | ||||
| parameters. | parameters. | ||||
| """ | """ | ||||
| replacement = HTMLEntity(value=ord(char)) | |||||
| replacement = str(HTMLEntity(value=ord(char))) | |||||
| for node in code.filter_text(recursive=False): | for node in code.filter_text(recursive=False): | ||||
| if char in node: | if char in node: | ||||
| code.replace(node, node.replace(char, replacement)) | code.replace(node, node.replace(char, replacement)) | ||||
| @@ -107,7 +107,7 @@ class Template(Node): | |||||
| values = tuple(theories.values()) | values = tuple(theories.values()) | ||||
| best = max(values) | best = max(values) | ||||
| confidence = float(best) / sum(values) | confidence = float(best) / sum(values) | ||||
| if confidence > 0.75: | |||||
| if confidence >= 0.75: | |||||
| return tuple(theories.keys())[values.index(best)] | return tuple(theories.keys())[values.index(best)] | ||||
| def _get_spacing_conventions(self, use_names): | def _get_spacing_conventions(self, use_names): | ||||
| @@ -142,9 +142,9 @@ class Template(Node): | |||||
| return False | return False | ||||
| return True | return True | ||||
| def _remove_without_field(self, param, i, force_no_field): | |||||
| def _remove_without_field(self, param, i): | |||||
| """Return False if a parameter name should be kept, otherwise True.""" | """Return False if a parameter name should be kept, otherwise True.""" | ||||
| if not param.showkey and not force_no_field: | |||||
| if not param.showkey: | |||||
| dependents = [not after.showkey for after in self.params[i+1:]] | dependents = [not after.showkey for after in self.params[i+1:]] | ||||
| if any(dependents): | if any(dependents): | ||||
| return False | return False | ||||
| @@ -183,11 +183,10 @@ class Template(Node): | |||||
| def get(self, name): | def get(self, name): | ||||
| """Get the parameter whose name is *name*. | """Get the parameter whose name is *name*. | ||||
| The returned object is a | |||||
| :py:class:`~.Parameter` instance. Raises :py:exc:`ValueError` if no | |||||
| parameter has this name. Since multiple parameters can have the same | |||||
| name, we'll return the last match, since the last parameter is the only | |||||
| one read by the MediaWiki parser. | |||||
| The returned object is a :py:class:`~.Parameter` instance. Raises | |||||
| :py:exc:`ValueError` if no parameter has this name. Since multiple | |||||
| parameters can have the same name, we'll return the last match, since | |||||
| the last parameter is the only one read by the MediaWiki parser. | |||||
| """ | """ | ||||
| name = name.strip() if isinstance(name, basestring) else str(name) | name = name.strip() if isinstance(name, basestring) else str(name) | ||||
| for param in reversed(self.params): | for param in reversed(self.params): | ||||
| @@ -195,20 +194,34 @@ class Template(Node): | |||||
| return param | return param | ||||
| raise ValueError(name) | raise ValueError(name) | ||||
| def add(self, name, value, showkey=None, force_nonconformity=False): | |||||
| def add(self, name, value, showkey=None, before=None, | |||||
| preserve_spacing=True): | |||||
| """Add a parameter to the template with a given *name* and *value*. | """Add a parameter to the template with a given *name* and *value*. | ||||
| *name* and *value* can be anything parasable by | *name* and *value* can be anything parasable by | ||||
| :py:func:`.utils.parse_anything`; pipes (and equal signs, if | |||||
| appropriate) are automatically escaped from *value* where applicable. | |||||
| :py:func:`.utils.parse_anything`; pipes and equal signs are | |||||
| automatically escaped from *value* when appropriate. | |||||
| If *showkey* is given, this will determine whether or not to show the | If *showkey* is given, this will determine whether or not to show the | ||||
| parameter's name (e.g., ``{{foo|bar}}``'s parameter has a name of | parameter's name (e.g., ``{{foo|bar}}``'s parameter has a name of | ||||
| ``"1"`` but it is hidden); otherwise, we'll make a safe and intelligent | ``"1"`` but it is hidden); otherwise, we'll make a safe and intelligent | ||||
| guess. If *name* is already a parameter, we'll replace its value while | |||||
| keeping the same spacing rules unless *force_nonconformity* is | |||||
| ``True``. We will also try to guess the dominant spacing convention | |||||
| when adding a new parameter using :py:meth:`_get_spacing_conventions` | |||||
| unless *force_nonconformity* is ``True``. | |||||
| guess. | |||||
| If *name* is already a parameter in the template, we'll replace its | |||||
| value while keeping the same whitespace around it. We will also try to | |||||
| guess the dominant spacing convention when adding a new parameter using | |||||
| :py:meth:`_get_spacing_conventions`. | |||||
| If *before* is given (either a :py:class:`~.Parameter` object or a | |||||
| name), then we will place the parameter immediately before this one. | |||||
| Otherwise, it will be added at the end. If *before* is a name and | |||||
| exists multiple times in the template, we will place it before the last | |||||
| occurance. If *before* is not in the template, :py:exc:`ValueError` is | |||||
| raised. The argument is ignored if the new parameter already exists. | |||||
| If *preserve_spacing* is ``False``, we will avoid preserving spacing | |||||
| conventions when changing the value of an existing parameter or when | |||||
| adding a new one. | |||||
| """ | """ | ||||
| name, value = parse_anything(name), parse_anything(value) | name, value = parse_anything(name), parse_anything(value) | ||||
| self._surface_escape(value, "|") | self._surface_escape(value, "|") | ||||
| @@ -217,14 +230,17 @@ class Template(Node): | |||||
| self.remove(name, keep_field=True) | self.remove(name, keep_field=True) | ||||
| existing = self.get(name) | existing = self.get(name) | ||||
| if showkey is not None: | if showkey is not None: | ||||
| if not showkey: | |||||
| self._surface_escape(value, "=") | |||||
| existing.showkey = showkey | existing.showkey = showkey | ||||
| if not existing.showkey: | |||||
| self._surface_escape(value, "=") | |||||
| nodes = existing.value.nodes | nodes = existing.value.nodes | ||||
| if force_nonconformity: | |||||
| existing.value = value | |||||
| else: | |||||
| if preserve_spacing: | |||||
| for i in range(2): # Ignore empty text nodes | |||||
| if not nodes[i]: | |||||
| nodes[i] = None | |||||
| existing.value = parse_anything([nodes[0], value, nodes[1]]) | existing.value = parse_anything([nodes[0], value, nodes[1]]) | ||||
| else: | |||||
| existing.value = value | |||||
| return existing | return existing | ||||
| if showkey is None: | if showkey is None: | ||||
| @@ -246,43 +262,38 @@ class Template(Node): | |||||
| if not showkey: | if not showkey: | ||||
| self._surface_escape(value, "=") | self._surface_escape(value, "=") | ||||
| if not force_nonconformity: | |||||
| if preserve_spacing: | |||||
| before_n, after_n = self._get_spacing_conventions(use_names=True) | before_n, after_n = self._get_spacing_conventions(use_names=True) | ||||
| if before_n and after_n: | |||||
| name = parse_anything([before_n, name, after_n]) | |||||
| elif before_n: | |||||
| name = parse_anything([before_n, name]) | |||||
| elif after_n: | |||||
| name = parse_anything([name, after_n]) | |||||
| before_v, after_v = self._get_spacing_conventions(use_names=False) | before_v, after_v = self._get_spacing_conventions(use_names=False) | ||||
| if before_v and after_v: | |||||
| value = parse_anything([before_v, value, after_v]) | |||||
| elif before_v: | |||||
| value = parse_anything([before_v, value]) | |||||
| elif after_v: | |||||
| value = parse_anything([value, after_v]) | |||||
| name = parse_anything([before_n, name, after_n]) | |||||
| value = parse_anything([before_v, value, after_v]) | |||||
| param = Parameter(name, value, showkey) | param = Parameter(name, value, showkey) | ||||
| self.params.append(param) | |||||
| if before: | |||||
| if not isinstance(before, Parameter): | |||||
| before = self.get(before) | |||||
| self.params.insert(self.params.index(before), param) | |||||
| else: | |||||
| self.params.append(param) | |||||
| return param | return param | ||||
| def remove(self, name, keep_field=False, force_no_field=False): | |||||
| def remove(self, name, keep_field=False): | |||||
| """Remove a parameter from the template whose name is *name*. | """Remove a parameter from the template whose name is *name*. | ||||
| If *keep_field* is ``True``, we will keep the parameter's name, but | If *keep_field* is ``True``, we will keep the parameter's name, but | ||||
| blank its value. Otherwise, we will remove the parameter completely | blank its value. Otherwise, we will remove the parameter completely | ||||
| *unless* other parameters are dependent on it (e.g. removing ``bar`` | *unless* other parameters are dependent on it (e.g. removing ``bar`` | ||||
| from ``{{foo|bar|baz}}`` is unsafe because ``{{foo|baz}}`` is not what | from ``{{foo|bar|baz}}`` is unsafe because ``{{foo|baz}}`` is not what | ||||
| we expected, so ``{{foo||baz}}`` will be produced instead), unless | |||||
| *force_no_field* is also ``True``. If the parameter shows up multiple | |||||
| times in the template, we will remove all instances of it (and keep | |||||
| one if *keep_field* is ``True`` - that being the first instance if | |||||
| none of the instances have dependents, otherwise that instance will be | |||||
| kept). | |||||
| we expected, so ``{{foo||baz}}`` will be produced instead). | |||||
| If the parameter shows up multiple times in the template, we will | |||||
| remove all instances of it (and keep one if *keep_field* is ``True`` - | |||||
| the first instance if none have dependents, otherwise the one with | |||||
| dependents will be kept). | |||||
| """ | """ | ||||
| name = name.strip() if isinstance(name, basestring) else str(name) | name = name.strip() if isinstance(name, basestring) else str(name) | ||||
| removed = False | removed = False | ||||
| to_remove =[] | |||||
| for i, param in enumerate(self.params): | for i, param in enumerate(self.params): | ||||
| if param.name.strip() == name: | if param.name.strip() == name: | ||||
| if keep_field: | if keep_field: | ||||
| @@ -290,13 +301,15 @@ class Template(Node): | |||||
| self._blank_param_value(param.value) | self._blank_param_value(param.value) | ||||
| keep_field = False | keep_field = False | ||||
| else: | else: | ||||
| self.params.remove(param) | |||||
| to_remove.append(param) | |||||
| else: | else: | ||||
| if self._remove_without_field(param, i, force_no_field): | |||||
| self.params.remove(param) | |||||
| if self._remove_without_field(param, i): | |||||
| to_remove.append(param) | |||||
| else: | else: | ||||
| self._blank_param_value(param.value) | self._blank_param_value(param.value) | ||||
| if not removed: | if not removed: | ||||
| removed = True | removed = True | ||||
| if not removed: | if not removed: | ||||
| raise ValueError(name) | raise ValueError(name) | ||||
| for param in to_remove: | |||||
| self.params.remove(param) | |||||
| @@ -79,4 +79,7 @@ class Wikilink(Node): | |||||
| @text.setter | @text.setter | ||||
| def text(self, value): | def text(self, value): | ||||
| self._text = parse_anything(value) | |||||
| if value is None: | |||||
| self._text = None | |||||
| else: | |||||
| self._text = parse_anything(value) | |||||
| @@ -88,13 +88,7 @@ class Wikicode(StringMixIn): | |||||
| If *obj* is a ``Node``, the function will test whether they are the | If *obj* is a ``Node``, the function will test whether they are the | ||||
| same object, otherwise it will compare them with ``==``. | same object, otherwise it will compare them with ``==``. | ||||
| """ | """ | ||||
| if isinstance(obj, Node): | |||||
| if node is obj: | |||||
| return True | |||||
| else: | |||||
| if node == obj: | |||||
| return True | |||||
| return False | |||||
| return (node is obj) if isinstance(obj, Node) else (node == obj) | |||||
| def _contains(self, nodes, obj): | def _contains(self, nodes, obj): | ||||
| """Return ``True`` if *obj* is inside of *nodes*, else ``False``. | """Return ``True`` if *obj* is inside of *nodes*, else ``False``. | ||||
| @@ -26,8 +26,21 @@ from unittest import TestCase | |||||
| from mwparserfromhell.nodes import (Argument, Comment, Heading, HTMLEntity, | from mwparserfromhell.nodes import (Argument, Comment, Heading, HTMLEntity, | ||||
| Tag, Template, Text, Wikilink) | Tag, Template, Text, Wikilink) | ||||
| from mwparserfromhell.nodes.extras import Attribute, Parameter | from mwparserfromhell.nodes.extras import Attribute, Parameter | ||||
| from mwparserfromhell.smart_list import SmartList | |||||
| from mwparserfromhell.wikicode import Wikicode | from mwparserfromhell.wikicode import Wikicode | ||||
| wrap = lambda L: Wikicode(SmartList(L)) | |||||
| wraptext = lambda *args: wrap([Text(t) for t in args]) | |||||
| def getnodes(code): | |||||
| """Iterate over all child nodes of a given parent node. | |||||
| Imitates Wikicode._get_all_nodes(). | |||||
| """ | |||||
| for node in code.nodes: | |||||
| for context, child in node.__iternodes__(getnodes): | |||||
| yield child | |||||
| class TreeEqualityTestCase(TestCase): | class TreeEqualityTestCase(TestCase): | ||||
| """A base test case with support for comparing the equality of node trees. | """A base test case with support for comparing the equality of node trees. | ||||
| @@ -0,0 +1,107 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import Argument, Text | |||||
| from ._test_tree_equality import TreeEqualityTestCase, getnodes, wrap, wraptext | |||||
| class TestArgument(TreeEqualityTestCase): | |||||
| """Test cases for the Argument node.""" | |||||
| def test_unicode(self): | |||||
| """test Argument.__unicode__()""" | |||||
| node = Argument(wraptext("foobar")) | |||||
| self.assertEqual("{{{foobar}}}", str(node)) | |||||
| node2 = Argument(wraptext("foo"), wraptext("bar")) | |||||
| self.assertEqual("{{{foo|bar}}}", str(node2)) | |||||
| def test_iternodes(self): | |||||
| """test Argument.__iternodes__()""" | |||||
| node1n1 = Text("foobar") | |||||
| node2n1, node2n2, node2n3 = Text("foo"), Text("bar"), Text("baz") | |||||
| node1 = Argument(wrap([node1n1])) | |||||
| node2 = Argument(wrap([node2n1]), wrap([node2n2, node2n3])) | |||||
| gen1 = node1.__iternodes__(getnodes) | |||||
| gen2 = node2.__iternodes__(getnodes) | |||||
| self.assertEqual((None, node1), next(gen1)) | |||||
| self.assertEqual((None, node2), next(gen2)) | |||||
| self.assertEqual((node1.name, node1n1), next(gen1)) | |||||
| self.assertEqual((node2.name, node2n1), next(gen2)) | |||||
| self.assertEqual((node2.default, node2n2), next(gen2)) | |||||
| self.assertEqual((node2.default, node2n3), next(gen2)) | |||||
| self.assertRaises(StopIteration, next, gen1) | |||||
| self.assertRaises(StopIteration, next, gen2) | |||||
| def test_strip(self): | |||||
| """test Argument.__strip__()""" | |||||
| node = Argument(wraptext("foobar")) | |||||
| node2 = Argument(wraptext("foo"), wraptext("bar")) | |||||
| for a in (True, False): | |||||
| for b in (True, False): | |||||
| self.assertIs(None, node.__strip__(a, b)) | |||||
| self.assertEqual("bar", node2.__strip__(a, b)) | |||||
| def test_showtree(self): | |||||
| """test Argument.__showtree__()""" | |||||
| output = [] | |||||
| getter, marker = object(), object() | |||||
| get = lambda code: output.append((getter, code)) | |||||
| mark = lambda: output.append(marker) | |||||
| node1 = Argument(wraptext("foobar")) | |||||
| node2 = Argument(wraptext("foo"), wraptext("bar")) | |||||
| node1.__showtree__(output.append, get, mark) | |||||
| node2.__showtree__(output.append, get, mark) | |||||
| valid = [ | |||||
| "{{{", (getter, node1.name), "}}}", "{{{", (getter, node2.name), | |||||
| " | ", marker, (getter, node2.default), "}}}"] | |||||
| self.assertEqual(valid, output) | |||||
| def test_name(self): | |||||
| """test getter/setter for the name attribute""" | |||||
| name = wraptext("foobar") | |||||
| node1 = Argument(name) | |||||
| node2 = Argument(name, wraptext("baz")) | |||||
| self.assertIs(name, node1.name) | |||||
| self.assertIs(name, node2.name) | |||||
| node1.name = "héhehé" | |||||
| node2.name = "héhehé" | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node1.name) | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node2.name) | |||||
| def test_default(self): | |||||
| """test getter/setter for the default attribute""" | |||||
| default = wraptext("baz") | |||||
| node1 = Argument(wraptext("foobar")) | |||||
| node2 = Argument(wraptext("foobar"), default) | |||||
| self.assertIs(None, node1.default) | |||||
| self.assertIs(default, node2.default) | |||||
| node1.default = "buzz" | |||||
| node2.default = None | |||||
| self.assertWikicodeEqual(wraptext("buzz"), node1.default) | |||||
| self.assertIs(None, node2.default) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||
| @@ -28,12 +28,8 @@ from mwparserfromhell.nodes import (Argument, Comment, Heading, HTMLEntity, | |||||
| from mwparserfromhell.nodes.extras import Attribute, Parameter | from mwparserfromhell.nodes.extras import Attribute, Parameter | ||||
| from mwparserfromhell.parser import tokens | from mwparserfromhell.parser import tokens | ||||
| from mwparserfromhell.parser.builder import Builder | from mwparserfromhell.parser.builder import Builder | ||||
| from mwparserfromhell.smart_list import SmartList | |||||
| from mwparserfromhell.wikicode import Wikicode | |||||
| from ._test_tree_equality import TreeEqualityTestCase | |||||
| wrap = lambda L: Wikicode(SmartList(L)) | |||||
| from ._test_tree_equality import TreeEqualityTestCase, wrap, wraptext | |||||
| class TestBuilder(TreeEqualityTestCase): | class TestBuilder(TreeEqualityTestCase): | ||||
| """Tests for the builder, which turns tokens into Wikicode objects.""" | """Tests for the builder, which turns tokens into Wikicode objects.""" | ||||
| @@ -44,10 +40,10 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| def test_text(self): | def test_text(self): | ||||
| """tests for building Text nodes""" | """tests for building Text nodes""" | ||||
| tests = [ | tests = [ | ||||
| ([tokens.Text(text="foobar")], wrap([Text("foobar")])), | |||||
| ([tokens.Text(text="fóóbar")], wrap([Text("fóóbar")])), | |||||
| ([tokens.Text(text="foobar")], wraptext("foobar")), | |||||
| ([tokens.Text(text="fóóbar")], wraptext("fóóbar")), | |||||
| ([tokens.Text(text="spam"), tokens.Text(text="eggs")], | ([tokens.Text(text="spam"), tokens.Text(text="eggs")], | ||||
| wrap([Text("spam"), Text("eggs")])), | |||||
| wraptext("spam", "eggs")), | |||||
| ] | ] | ||||
| for test, valid in tests: | for test, valid in tests: | ||||
| self.assertWikicodeEqual(valid, self.builder.build(test)) | self.assertWikicodeEqual(valid, self.builder.build(test)) | ||||
| @@ -57,25 +53,24 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tests = [ | tests = [ | ||||
| ([tokens.TemplateOpen(), tokens.Text(text="foobar"), | ([tokens.TemplateOpen(), tokens.Text(text="foobar"), | ||||
| tokens.TemplateClose()], | tokens.TemplateClose()], | ||||
| wrap([Template(wrap([Text("foobar")]))])), | |||||
| wrap([Template(wraptext("foobar"))])), | |||||
| ([tokens.TemplateOpen(), tokens.Text(text="spam"), | ([tokens.TemplateOpen(), tokens.Text(text="spam"), | ||||
| tokens.Text(text="eggs"), tokens.TemplateClose()], | tokens.Text(text="eggs"), tokens.TemplateClose()], | ||||
| wrap([Template(wrap([Text("spam"), Text("eggs")]))])), | |||||
| wrap([Template(wraptext("spam", "eggs"))])), | |||||
| ([tokens.TemplateOpen(), tokens.Text(text="foo"), | ([tokens.TemplateOpen(), tokens.Text(text="foo"), | ||||
| tokens.TemplateParamSeparator(), tokens.Text(text="bar"), | tokens.TemplateParamSeparator(), tokens.Text(text="bar"), | ||||
| tokens.TemplateClose()], | tokens.TemplateClose()], | ||||
| wrap([Template(wrap([Text("foo")]), params=[ | |||||
| Parameter(wrap([Text("1")]), wrap([Text("bar")]), | |||||
| showkey=False)])])), | |||||
| wrap([Template(wraptext("foo"), params=[ | |||||
| Parameter(wraptext("1"), wraptext("bar"), showkey=False)])])), | |||||
| ([tokens.TemplateOpen(), tokens.Text(text="foo"), | ([tokens.TemplateOpen(), tokens.Text(text="foo"), | ||||
| tokens.TemplateParamSeparator(), tokens.Text(text="bar"), | tokens.TemplateParamSeparator(), tokens.Text(text="bar"), | ||||
| tokens.TemplateParamEquals(), tokens.Text(text="baz"), | tokens.TemplateParamEquals(), tokens.Text(text="baz"), | ||||
| tokens.TemplateClose()], | tokens.TemplateClose()], | ||||
| wrap([Template(wrap([Text("foo")]), params=[ | |||||
| Parameter(wrap([Text("bar")]), wrap([Text("baz")]))])])), | |||||
| wrap([Template(wraptext("foo"), params=[ | |||||
| Parameter(wraptext("bar"), wraptext("baz"))])])), | |||||
| ([tokens.TemplateOpen(), tokens.Text(text="foo"), | ([tokens.TemplateOpen(), tokens.Text(text="foo"), | ||||
| tokens.TemplateParamSeparator(), tokens.Text(text="bar"), | tokens.TemplateParamSeparator(), tokens.Text(text="bar"), | ||||
| @@ -86,14 +81,12 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tokens.TemplateParamEquals(), tokens.Text(text="buff"), | tokens.TemplateParamEquals(), tokens.Text(text="buff"), | ||||
| tokens.TemplateParamSeparator(), tokens.Text(text="baff"), | tokens.TemplateParamSeparator(), tokens.Text(text="baff"), | ||||
| tokens.TemplateClose()], | tokens.TemplateClose()], | ||||
| wrap([Template(wrap([Text("foo")]), params=[ | |||||
| Parameter(wrap([Text("bar")]), wrap([Text("baz")])), | |||||
| Parameter(wrap([Text("1")]), wrap([Text("biz")]), | |||||
| showkey=False), | |||||
| Parameter(wrap([Text("2")]), wrap([Text("buzz")]), | |||||
| showkey=False), | |||||
| Parameter(wrap([Text("3")]), wrap([Text("buff")])), | |||||
| Parameter(wrap([Text("3")]), wrap([Text("baff")]), | |||||
| wrap([Template(wraptext("foo"), params=[ | |||||
| Parameter(wraptext("bar"), wraptext("baz")), | |||||
| Parameter(wraptext("1"), wraptext("biz"), showkey=False), | |||||
| Parameter(wraptext("2"), wraptext("buzz"), showkey=False), | |||||
| Parameter(wraptext("3"), wraptext("buff")), | |||||
| Parameter(wraptext("3"), wraptext("baff"), | |||||
| showkey=False)])])), | showkey=False)])])), | ||||
| ] | ] | ||||
| for test, valid in tests: | for test, valid in tests: | ||||
| @@ -104,23 +97,22 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tests = [ | tests = [ | ||||
| ([tokens.ArgumentOpen(), tokens.Text(text="foobar"), | ([tokens.ArgumentOpen(), tokens.Text(text="foobar"), | ||||
| tokens.ArgumentClose()], | tokens.ArgumentClose()], | ||||
| wrap([Argument(wrap([Text("foobar")]))])), | |||||
| wrap([Argument(wraptext("foobar"))])), | |||||
| ([tokens.ArgumentOpen(), tokens.Text(text="spam"), | ([tokens.ArgumentOpen(), tokens.Text(text="spam"), | ||||
| tokens.Text(text="eggs"), tokens.ArgumentClose()], | tokens.Text(text="eggs"), tokens.ArgumentClose()], | ||||
| wrap([Argument(wrap([Text("spam"), Text("eggs")]))])), | |||||
| wrap([Argument(wraptext("spam", "eggs"))])), | |||||
| ([tokens.ArgumentOpen(), tokens.Text(text="foo"), | ([tokens.ArgumentOpen(), tokens.Text(text="foo"), | ||||
| tokens.ArgumentSeparator(), tokens.Text(text="bar"), | tokens.ArgumentSeparator(), tokens.Text(text="bar"), | ||||
| tokens.ArgumentClose()], | tokens.ArgumentClose()], | ||||
| wrap([Argument(wrap([Text("foo")]), wrap([Text("bar")]))])), | |||||
| wrap([Argument(wraptext("foo"), wraptext("bar"))])), | |||||
| ([tokens.ArgumentOpen(), tokens.Text(text="foo"), | ([tokens.ArgumentOpen(), tokens.Text(text="foo"), | ||||
| tokens.Text(text="bar"), tokens.ArgumentSeparator(), | tokens.Text(text="bar"), tokens.ArgumentSeparator(), | ||||
| tokens.Text(text="baz"), tokens.Text(text="biz"), | tokens.Text(text="baz"), tokens.Text(text="biz"), | ||||
| tokens.ArgumentClose()], | tokens.ArgumentClose()], | ||||
| wrap([Argument(wrap([Text("foo"), Text("bar")]), | |||||
| wrap([Text("baz"), Text("biz")]))])), | |||||
| wrap([Argument(wraptext("foo", "bar"), wraptext("baz", "biz"))])), | |||||
| ] | ] | ||||
| for test, valid in tests: | for test, valid in tests: | ||||
| self.assertWikicodeEqual(valid, self.builder.build(test)) | self.assertWikicodeEqual(valid, self.builder.build(test)) | ||||
| @@ -130,23 +122,22 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tests = [ | tests = [ | ||||
| ([tokens.WikilinkOpen(), tokens.Text(text="foobar"), | ([tokens.WikilinkOpen(), tokens.Text(text="foobar"), | ||||
| tokens.WikilinkClose()], | tokens.WikilinkClose()], | ||||
| wrap([Wikilink(wrap([Text("foobar")]))])), | |||||
| wrap([Wikilink(wraptext("foobar"))])), | |||||
| ([tokens.WikilinkOpen(), tokens.Text(text="spam"), | ([tokens.WikilinkOpen(), tokens.Text(text="spam"), | ||||
| tokens.Text(text="eggs"), tokens.WikilinkClose()], | tokens.Text(text="eggs"), tokens.WikilinkClose()], | ||||
| wrap([Wikilink(wrap([Text("spam"), Text("eggs")]))])), | |||||
| wrap([Wikilink(wraptext("spam", "eggs"))])), | |||||
| ([tokens.WikilinkOpen(), tokens.Text(text="foo"), | ([tokens.WikilinkOpen(), tokens.Text(text="foo"), | ||||
| tokens.WikilinkSeparator(), tokens.Text(text="bar"), | tokens.WikilinkSeparator(), tokens.Text(text="bar"), | ||||
| tokens.WikilinkClose()], | tokens.WikilinkClose()], | ||||
| wrap([Wikilink(wrap([Text("foo")]), wrap([Text("bar")]))])), | |||||
| wrap([Wikilink(wraptext("foo"), wraptext("bar"))])), | |||||
| ([tokens.WikilinkOpen(), tokens.Text(text="foo"), | ([tokens.WikilinkOpen(), tokens.Text(text="foo"), | ||||
| tokens.Text(text="bar"), tokens.WikilinkSeparator(), | tokens.Text(text="bar"), tokens.WikilinkSeparator(), | ||||
| tokens.Text(text="baz"), tokens.Text(text="biz"), | tokens.Text(text="baz"), tokens.Text(text="biz"), | ||||
| tokens.WikilinkClose()], | tokens.WikilinkClose()], | ||||
| wrap([Wikilink(wrap([Text("foo"), Text("bar")]), | |||||
| wrap([Text("baz"), Text("biz")]))])), | |||||
| wrap([Wikilink(wraptext("foo", "bar"), wraptext("baz", "biz"))])), | |||||
| ] | ] | ||||
| for test, valid in tests: | for test, valid in tests: | ||||
| self.assertWikicodeEqual(valid, self.builder.build(test)) | self.assertWikicodeEqual(valid, self.builder.build(test)) | ||||
| @@ -176,11 +167,11 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tests = [ | tests = [ | ||||
| ([tokens.HeadingStart(level=2), tokens.Text(text="foobar"), | ([tokens.HeadingStart(level=2), tokens.Text(text="foobar"), | ||||
| tokens.HeadingEnd()], | tokens.HeadingEnd()], | ||||
| wrap([Heading(wrap([Text("foobar")]), 2)])), | |||||
| wrap([Heading(wraptext("foobar"), 2)])), | |||||
| ([tokens.HeadingStart(level=4), tokens.Text(text="spam"), | ([tokens.HeadingStart(level=4), tokens.Text(text="spam"), | ||||
| tokens.Text(text="eggs"), tokens.HeadingEnd()], | tokens.Text(text="eggs"), tokens.HeadingEnd()], | ||||
| wrap([Heading(wrap([Text("spam"), Text("eggs")]), 4)])), | |||||
| wrap([Heading(wraptext("spam", "eggs"), 4)])), | |||||
| ] | ] | ||||
| for test, valid in tests: | for test, valid in tests: | ||||
| self.assertWikicodeEqual(valid, self.builder.build(test)) | self.assertWikicodeEqual(valid, self.builder.build(test)) | ||||
| @@ -190,11 +181,11 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tests = [ | tests = [ | ||||
| ([tokens.CommentStart(), tokens.Text(text="foobar"), | ([tokens.CommentStart(), tokens.Text(text="foobar"), | ||||
| tokens.CommentEnd()], | tokens.CommentEnd()], | ||||
| wrap([Comment(wrap([Text("foobar")]))])), | |||||
| wrap([Comment(wraptext("foobar"))])), | |||||
| ([tokens.CommentStart(), tokens.Text(text="spam"), | ([tokens.CommentStart(), tokens.Text(text="spam"), | ||||
| tokens.Text(text="eggs"), tokens.CommentEnd()], | tokens.Text(text="eggs"), tokens.CommentEnd()], | ||||
| wrap([Comment(wrap([Text("spam"), Text("eggs")]))])), | |||||
| wrap([Comment(wraptext("spam", "eggs"))])), | |||||
| ] | ] | ||||
| for test, valid in tests: | for test, valid in tests: | ||||
| self.assertWikicodeEqual(valid, self.builder.build(test)) | self.assertWikicodeEqual(valid, self.builder.build(test)) | ||||
| @@ -218,10 +209,10 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tokens.TemplateOpen(), tokens.Text(text="bin"), | tokens.TemplateOpen(), tokens.Text(text="bin"), | ||||
| tokens.TemplateClose(), tokens.TemplateClose()] | tokens.TemplateClose(), tokens.TemplateClose()] | ||||
| valid = wrap( | valid = wrap( | ||||
| [Template(wrap([Template(wrap([Template(wrap([Template(wrap([Text( | |||||
| "foo")])), Text("bar")]), params=[Parameter(wrap([Text("baz")]), | |||||
| wrap([Text("biz")]))]), Text("buzz")])), Text("usr")]), params=[ | |||||
| Parameter(wrap([Text("1")]), wrap([Template(wrap([Text("bin")]))]), | |||||
| [Template(wrap([Template(wrap([Template(wrap([Template(wraptext( | |||||
| "foo")), Text("bar")]), params=[Parameter(wraptext("baz"), | |||||
| wraptext("biz"))]), Text("buzz")])), Text("usr")]), params=[ | |||||
| Parameter(wraptext("1"), wrap([Template(wraptext("bin"))]), | |||||
| showkey=False)])]) | showkey=False)])]) | ||||
| self.assertWikicodeEqual(valid, self.builder.build(test)) | self.assertWikicodeEqual(valid, self.builder.build(test)) | ||||
| @@ -247,14 +238,14 @@ class TestBuilder(TreeEqualityTestCase): | |||||
| tokens.Text(text="nbsp"), tokens.HTMLEntityEnd(), | tokens.Text(text="nbsp"), tokens.HTMLEntityEnd(), | ||||
| tokens.TemplateClose()] | tokens.TemplateClose()] | ||||
| valid = wrap( | valid = wrap( | ||||
| [Template(wrap([Text("a")]), params=[Parameter(wrap([Text("1")]), | |||||
| wrap([Text("b")]), showkey=False), Parameter(wrap([Text("2")]), | |||||
| wrap([Template(wrap([Text("c")]), params=[Parameter(wrap([Text("1") | |||||
| ]), wrap([Wikilink(wrap([Text("d")])), Argument(wrap([Text("e")]))] | |||||
| ), showkey=False)])]), showkey=False)]), Wikilink(wrap([Text("f")] | |||||
| ), wrap([Argument(wrap([Text("g")])), Comment(wrap([Text("h")]))]) | |||||
| ), Template(wrap([Text("i")]), params=[Parameter(wrap([Text("j")]), | |||||
| wrap([HTMLEntity("nbsp", named=True)]))])]) | |||||
| [Template(wraptext("a"), params=[Parameter(wraptext("1"), wraptext( | |||||
| "b"), showkey=False), Parameter(wraptext("2"), wrap([Template( | |||||
| wraptext("c"), params=[Parameter(wraptext("1"), wrap([Wikilink( | |||||
| wraptext("d")), Argument(wraptext("e"))]), showkey=False)])]), | |||||
| showkey=False)]), Wikilink(wraptext("f"), wrap([Argument(wraptext( | |||||
| "g")), Comment(wraptext("h"))])), Template(wraptext("i"), params=[ | |||||
| Parameter(wraptext("j"), wrap([HTMLEntity("nbsp", | |||||
| named=True)]))])]) | |||||
| self.assertWikicodeEqual(valid, self.builder.build(test)) | self.assertWikicodeEqual(valid, self.builder.build(test)) | ||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||
| @@ -0,0 +1,68 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import Comment | |||||
| from ._test_tree_equality import TreeEqualityTestCase | |||||
| class TestComment(TreeEqualityTestCase): | |||||
| """Test cases for the Comment node.""" | |||||
| def test_unicode(self): | |||||
| """test Comment.__unicode__()""" | |||||
| node = Comment("foobar") | |||||
| self.assertEqual("<!--foobar-->", str(node)) | |||||
| def test_iternodes(self): | |||||
| """test Comment.__iternodes__()""" | |||||
| node = Comment("foobar") | |||||
| gen = node.__iternodes__(None) | |||||
| self.assertEqual((None, node), next(gen)) | |||||
| self.assertRaises(StopIteration, next, gen) | |||||
| def test_strip(self): | |||||
| """test Comment.__strip__()""" | |||||
| node = Comment("foobar") | |||||
| for a in (True, False): | |||||
| for b in (True, False): | |||||
| self.assertIs(None, node.__strip__(a, b)) | |||||
| def test_showtree(self): | |||||
| """test Comment.__showtree__()""" | |||||
| output = [] | |||||
| node = Comment("foobar") | |||||
| node.__showtree__(output.append, None, None) | |||||
| self.assertEqual(["<!--foobar-->"], output) | |||||
| def test_contents(self): | |||||
| """test getter/setter for the contents attribute""" | |||||
| node = Comment("foobar") | |||||
| self.assertEqual("foobar", node.contents) | |||||
| node.contents = "barfoo" | |||||
| self.assertEqual("barfoo", node.contents) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||
| @@ -0,0 +1,91 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import Heading, Text | |||||
| from ._test_tree_equality import TreeEqualityTestCase, getnodes, wrap, wraptext | |||||
| class TestHeading(TreeEqualityTestCase): | |||||
| """Test cases for the Heading node.""" | |||||
| def test_unicode(self): | |||||
| """test Heading.__unicode__()""" | |||||
| node = Heading(wraptext("foobar"), 2) | |||||
| self.assertEqual("==foobar==", str(node)) | |||||
| node2 = Heading(wraptext(" zzz "), 5) | |||||
| self.assertEqual("===== zzz =====", str(node2)) | |||||
| def test_iternodes(self): | |||||
| """test Heading.__iternodes__()""" | |||||
| text1, text2 = Text("foo"), Text("bar") | |||||
| node = Heading(wrap([text1, text2]), 3) | |||||
| gen = node.__iternodes__(getnodes) | |||||
| self.assertEqual((None, node), next(gen)) | |||||
| self.assertEqual((node.title, text1), next(gen)) | |||||
| self.assertEqual((node.title, text2), next(gen)) | |||||
| self.assertRaises(StopIteration, next, gen) | |||||
| def test_strip(self): | |||||
| """test Heading.__strip__()""" | |||||
| node = Heading(wraptext("foobar"), 3) | |||||
| for a in (True, False): | |||||
| for b in (True, False): | |||||
| self.assertEqual("foobar", node.__strip__(a, b)) | |||||
| def test_showtree(self): | |||||
| """test Heading.__showtree__()""" | |||||
| output = [] | |||||
| getter = object() | |||||
| get = lambda code: output.append((getter, code)) | |||||
| node1 = Heading(wraptext("foobar"), 3) | |||||
| node2 = Heading(wraptext(" baz "), 4) | |||||
| node1.__showtree__(output.append, get, None) | |||||
| node2.__showtree__(output.append, get, None) | |||||
| valid = ["===", (getter, node1.title), "===", | |||||
| "====", (getter, node2.title), "===="] | |||||
| self.assertEqual(valid, output) | |||||
| def test_title(self): | |||||
| """test getter/setter for the title attribute""" | |||||
| title = wraptext("foobar") | |||||
| node = Heading(title, 3) | |||||
| self.assertIs(title, node.title) | |||||
| node.title = "héhehé" | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node.title) | |||||
| def test_level(self): | |||||
| """test getter/setter for the level attribute""" | |||||
| node = Heading(wraptext("foobar"), 3) | |||||
| self.assertEqual(3, node.level) | |||||
| node.level = 5 | |||||
| self.assertEqual(5, node.level) | |||||
| self.assertRaises(ValueError, setattr, node, "level", 0) | |||||
| self.assertRaises(ValueError, setattr, node, "level", 7) | |||||
| self.assertRaises(ValueError, setattr, node, "level", "abc") | |||||
| self.assertRaises(ValueError, setattr, node, "level", False) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||
| @@ -0,0 +1,169 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import HTMLEntity | |||||
| from ._test_tree_equality import TreeEqualityTestCase, wrap | |||||
| class TestHTMLEntity(TreeEqualityTestCase): | |||||
| """Test cases for the HTMLEntity node.""" | |||||
| def test_unicode(self): | |||||
| """test HTMLEntity.__unicode__()""" | |||||
| node1 = HTMLEntity("nbsp", named=True, hexadecimal=False) | |||||
| node2 = HTMLEntity("107", named=False, hexadecimal=False) | |||||
| node3 = HTMLEntity("6b", named=False, hexadecimal=True) | |||||
| node4 = HTMLEntity("6C", named=False, hexadecimal=True, hex_char="X") | |||||
| self.assertEqual(" ", str(node1)) | |||||
| self.assertEqual("k", str(node2)) | |||||
| self.assertEqual("k", str(node3)) | |||||
| self.assertEqual("l", str(node4)) | |||||
| def test_iternodes(self): | |||||
| """test HTMLEntity.__iternodes__()""" | |||||
| node = HTMLEntity("nbsp", named=True, hexadecimal=False) | |||||
| gen = node.__iternodes__(None) | |||||
| self.assertEqual((None, node), next(gen)) | |||||
| self.assertRaises(StopIteration, next, gen) | |||||
| def test_strip(self): | |||||
| """test HTMLEntity.__strip__()""" | |||||
| node1 = HTMLEntity("nbsp", named=True, hexadecimal=False) | |||||
| node2 = HTMLEntity("107", named=False, hexadecimal=False) | |||||
| node3 = HTMLEntity("e9", named=False, hexadecimal=True) | |||||
| for a in (True, False): | |||||
| self.assertEqual("\xa0", node1.__strip__(True, a)) | |||||
| self.assertEqual(" ", node1.__strip__(False, a)) | |||||
| self.assertEqual("k", node2.__strip__(True, a)) | |||||
| self.assertEqual("k", node2.__strip__(False, a)) | |||||
| self.assertEqual("é", node3.__strip__(True, a)) | |||||
| self.assertEqual("é", node3.__strip__(False, a)) | |||||
| def test_showtree(self): | |||||
| """test HTMLEntity.__showtree__()""" | |||||
| output = [] | |||||
| node1 = HTMLEntity("nbsp", named=True, hexadecimal=False) | |||||
| node2 = HTMLEntity("107", named=False, hexadecimal=False) | |||||
| node3 = HTMLEntity("e9", named=False, hexadecimal=True) | |||||
| node1.__showtree__(output.append, None, None) | |||||
| node2.__showtree__(output.append, None, None) | |||||
| node3.__showtree__(output.append, None, None) | |||||
| res = [" ", "k", "é"] | |||||
| self.assertEqual(res, output) | |||||
| def test_value(self): | |||||
| """test getter/setter for the value attribute""" | |||||
| node1 = HTMLEntity("nbsp") | |||||
| node2 = HTMLEntity("107") | |||||
| node3 = HTMLEntity("e9") | |||||
| self.assertEqual("nbsp", node1.value) | |||||
| self.assertEqual("107", node2.value) | |||||
| self.assertEqual("e9", node3.value) | |||||
| node1.value = "ffa4" | |||||
| node2.value = 72 | |||||
| node3.value = "Sigma" | |||||
| self.assertEqual("ffa4", node1.value) | |||||
| self.assertFalse(node1.named) | |||||
| self.assertTrue(node1.hexadecimal) | |||||
| self.assertEqual("72", node2.value) | |||||
| self.assertFalse(node2.named) | |||||
| self.assertFalse(node2.hexadecimal) | |||||
| self.assertEqual("Sigma", node3.value) | |||||
| self.assertTrue(node3.named) | |||||
| self.assertFalse(node3.hexadecimal) | |||||
| node1.value = "10FFFF" | |||||
| node2.value = 110000 | |||||
| node2.value = 1114111 | |||||
| self.assertRaises(ValueError, setattr, node3, "value", "") | |||||
| self.assertRaises(ValueError, setattr, node3, "value", "foobar") | |||||
| self.assertRaises(ValueError, setattr, node3, "value", True) | |||||
| self.assertRaises(ValueError, setattr, node3, "value", -1) | |||||
| self.assertRaises(ValueError, setattr, node1, "value", 110000) | |||||
| self.assertRaises(ValueError, setattr, node1, "value", "1114112") | |||||
| def test_named(self): | |||||
| """test getter/setter for the named attribute""" | |||||
| node1 = HTMLEntity("nbsp") | |||||
| node2 = HTMLEntity("107") | |||||
| node3 = HTMLEntity("e9") | |||||
| self.assertTrue(node1.named) | |||||
| self.assertFalse(node2.named) | |||||
| self.assertFalse(node3.named) | |||||
| node1.named = 1 | |||||
| node2.named = 0 | |||||
| node3.named = 0 | |||||
| self.assertTrue(node1.named) | |||||
| self.assertFalse(node2.named) | |||||
| self.assertFalse(node3.named) | |||||
| self.assertRaises(ValueError, setattr, node1, "named", False) | |||||
| self.assertRaises(ValueError, setattr, node2, "named", True) | |||||
| self.assertRaises(ValueError, setattr, node3, "named", True) | |||||
| def test_hexadecimal(self): | |||||
| """test getter/setter for the hexadecimal attribute""" | |||||
| node1 = HTMLEntity("nbsp") | |||||
| node2 = HTMLEntity("107") | |||||
| node3 = HTMLEntity("e9") | |||||
| self.assertFalse(node1.hexadecimal) | |||||
| self.assertFalse(node2.hexadecimal) | |||||
| self.assertTrue(node3.hexadecimal) | |||||
| node1.hexadecimal = False | |||||
| node2.hexadecimal = True | |||||
| node3.hexadecimal = False | |||||
| self.assertFalse(node1.hexadecimal) | |||||
| self.assertTrue(node2.hexadecimal) | |||||
| self.assertFalse(node3.hexadecimal) | |||||
| self.assertRaises(ValueError, setattr, node1, "hexadecimal", True) | |||||
| def test_hex_char(self): | |||||
| """test getter/setter for the hex_char attribute""" | |||||
| node1 = HTMLEntity("e9") | |||||
| node2 = HTMLEntity("e9", hex_char="X") | |||||
| self.assertEqual("x", node1.hex_char) | |||||
| self.assertEqual("X", node2.hex_char) | |||||
| node1.hex_char = "X" | |||||
| node2.hex_char = "x" | |||||
| self.assertEqual("X", node1.hex_char) | |||||
| self.assertEqual("x", node2.hex_char) | |||||
| self.assertRaises(ValueError, setattr, node1, "hex_char", 123) | |||||
| self.assertRaises(ValueError, setattr, node1, "hex_char", "foobar") | |||||
| self.assertRaises(ValueError, setattr, node1, "hex_char", True) | |||||
| def test_normalize(self): | |||||
| """test getter/setter for the normalize attribute""" | |||||
| node1 = HTMLEntity("nbsp") | |||||
| node2 = HTMLEntity("107") | |||||
| node3 = HTMLEntity("e9") | |||||
| node4 = HTMLEntity("1f648") | |||||
| self.assertEqual("\xa0", node1.normalize()) | |||||
| self.assertEqual("k", node2.normalize()) | |||||
| self.assertEqual("é", node3.normalize()) | |||||
| self.assertEqual("\U0001F648", node4.normalize()) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||
| @@ -0,0 +1,75 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import Text | |||||
| from mwparserfromhell.nodes.extras import Parameter | |||||
| from ._test_tree_equality import TreeEqualityTestCase, wrap, wraptext | |||||
| class TestParameter(TreeEqualityTestCase): | |||||
| """Test cases for the Parameter node extra.""" | |||||
| def test_unicode(self): | |||||
| """test Parameter.__unicode__()""" | |||||
| node = Parameter(wraptext("1"), wraptext("foo"), showkey=False) | |||||
| self.assertEqual("foo", str(node)) | |||||
| node2 = Parameter(wraptext("foo"), wraptext("bar")) | |||||
| self.assertEqual("foo=bar", str(node2)) | |||||
| def test_name(self): | |||||
| """test getter/setter for the name attribute""" | |||||
| name1 = wraptext("1") | |||||
| name2 = wraptext("foobar") | |||||
| node1 = Parameter(name1, wraptext("foobar"), showkey=False) | |||||
| node2 = Parameter(name2, wraptext("baz")) | |||||
| self.assertIs(name1, node1.name) | |||||
| self.assertIs(name2, node2.name) | |||||
| node1.name = "héhehé" | |||||
| node2.name = "héhehé" | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node1.name) | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node2.name) | |||||
| def test_value(self): | |||||
| """test getter/setter for the value attribute""" | |||||
| value = wraptext("bar") | |||||
| node = Parameter(wraptext("foo"), value) | |||||
| self.assertIs(value, node.value) | |||||
| node.value = "héhehé" | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node.value) | |||||
| def test_showkey(self): | |||||
| """test getter/setter for the showkey attribute""" | |||||
| node1 = Parameter(wraptext("1"), wraptext("foo"), showkey=False) | |||||
| node2 = Parameter(wraptext("foo"), wraptext("bar")) | |||||
| self.assertFalse(node1.showkey) | |||||
| self.assertTrue(node2.showkey) | |||||
| node1.showkey = True | |||||
| node2.showkey = "" | |||||
| self.assertTrue(node1.showkey) | |||||
| self.assertFalse(node2.showkey) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||
| @@ -26,10 +26,8 @@ import unittest | |||||
| from mwparserfromhell import parser | from mwparserfromhell import parser | ||||
| from mwparserfromhell.nodes import Template, Text, Wikilink | from mwparserfromhell.nodes import Template, Text, Wikilink | ||||
| from mwparserfromhell.nodes.extras import Parameter | from mwparserfromhell.nodes.extras import Parameter | ||||
| from mwparserfromhell.smart_list import SmartList | |||||
| from mwparserfromhell.wikicode import Wikicode | |||||
| from ._test_tree_equality import TreeEqualityTestCase | |||||
| from ._test_tree_equality import TreeEqualityTestCase, wrap, wraptext | |||||
| from .compat import range | from .compat import range | ||||
| class TestParser(TreeEqualityTestCase): | class TestParser(TreeEqualityTestCase): | ||||
| @@ -45,18 +43,17 @@ class TestParser(TreeEqualityTestCase): | |||||
| def test_parsing(self): | def test_parsing(self): | ||||
| """integration test for parsing overall""" | """integration test for parsing overall""" | ||||
| text = "this is text; {{this|is=a|template={{with|[[links]]|in}}it}}" | text = "this is text; {{this|is=a|template={{with|[[links]]|in}}it}}" | ||||
| wrap = lambda L: Wikicode(SmartList(L)) | |||||
| expected = wrap([ | expected = wrap([ | ||||
| Text("this is text; "), | Text("this is text; "), | ||||
| Template(wrap([Text("this")]), [ | |||||
| Parameter(wrap([Text("is")]), wrap([Text("a")])), | |||||
| Parameter(wrap([Text("template")]), wrap([ | |||||
| Template(wrap([Text("with")]), [ | |||||
| Parameter(wrap([Text("1")]), | |||||
| wrap([Wikilink(wrap([Text("links")]))]), | |||||
| Template(wraptext("this"), [ | |||||
| Parameter(wraptext("is"), wraptext("a")), | |||||
| Parameter(wraptext("template"), wrap([ | |||||
| Template(wraptext("with"), [ | |||||
| Parameter(wraptext("1"), | |||||
| wrap([Wikilink(wraptext("links"))]), | |||||
| showkey=False), | showkey=False), | ||||
| Parameter(wrap([Text("2")]), | |||||
| wrap([Text("in")]), showkey=False) | |||||
| Parameter(wraptext("2"), | |||||
| wraptext("in"), showkey=False) | |||||
| ]), | ]), | ||||
| Text("it") | Text("it") | ||||
| ])) | ])) | ||||
| @@ -0,0 +1,364 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import HTMLEntity, Template, Text | |||||
| from mwparserfromhell.nodes.extras import Parameter | |||||
| from ._test_tree_equality import TreeEqualityTestCase, getnodes, wrap, wraptext | |||||
| pgens = lambda k, v: Parameter(wraptext(k), wraptext(v), showkey=True) | |||||
| pgenh = lambda k, v: Parameter(wraptext(k), wraptext(v), showkey=False) | |||||
| class TestTemplate(TreeEqualityTestCase): | |||||
| """Test cases for the Template node.""" | |||||
| def test_unicode(self): | |||||
| """test Template.__unicode__()""" | |||||
| node = Template(wraptext("foobar")) | |||||
| self.assertEqual("{{foobar}}", str(node)) | |||||
| node2 = Template(wraptext("foo"), | |||||
| [pgenh("1", "bar"), pgens("abc", "def")]) | |||||
| self.assertEqual("{{foo|bar|abc=def}}", str(node2)) | |||||
| def test_iternodes(self): | |||||
| """test Template.__iternodes__()""" | |||||
| node1n1 = Text("foobar") | |||||
| node2n1, node2n2, node2n3 = Text("foo"), Text("bar"), Text("abc") | |||||
| node2n4, node2n5 = Text("def"), Text("ghi") | |||||
| node2p1 = Parameter(wraptext("1"), wrap([node2n2]), showkey=False) | |||||
| node2p2 = Parameter(wrap([node2n3]), wrap([node2n4, node2n5]), | |||||
| showkey=True) | |||||
| node1 = Template(wrap([node1n1])) | |||||
| node2 = Template(wrap([node2n1]), [node2p1, node2p2]) | |||||
| gen1 = node1.__iternodes__(getnodes) | |||||
| gen2 = node2.__iternodes__(getnodes) | |||||
| self.assertEqual((None, node1), next(gen1)) | |||||
| self.assertEqual((None, node2), next(gen2)) | |||||
| self.assertEqual((node1.name, node1n1), next(gen1)) | |||||
| self.assertEqual((node2.name, node2n1), next(gen2)) | |||||
| self.assertEqual((node2.params[0].value, node2n2), next(gen2)) | |||||
| self.assertEqual((node2.params[1].name, node2n3), next(gen2)) | |||||
| self.assertEqual((node2.params[1].value, node2n4), next(gen2)) | |||||
| self.assertEqual((node2.params[1].value, node2n5), next(gen2)) | |||||
| self.assertRaises(StopIteration, next, gen1) | |||||
| self.assertRaises(StopIteration, next, gen2) | |||||
| def test_strip(self): | |||||
| """test Template.__strip__()""" | |||||
| node1 = Template(wraptext("foobar")) | |||||
| node2 = Template(wraptext("foo"), | |||||
| [pgenh("1", "bar"), pgens("abc", "def")]) | |||||
| for a in (True, False): | |||||
| for b in (True, False): | |||||
| self.assertEqual(None, node1.__strip__(a, b)) | |||||
| self.assertEqual(None, node2.__strip__(a, b)) | |||||
| def test_showtree(self): | |||||
| """test Template.__showtree__()""" | |||||
| output = [] | |||||
| getter, marker = object(), object() | |||||
| get = lambda code: output.append((getter, code)) | |||||
| mark = lambda: output.append(marker) | |||||
| node1 = Template(wraptext("foobar")) | |||||
| node2 = Template(wraptext("foo"), | |||||
| [pgenh("1", "bar"), pgens("abc", "def")]) | |||||
| node1.__showtree__(output.append, get, mark) | |||||
| node2.__showtree__(output.append, get, mark) | |||||
| valid = [ | |||||
| "{{", (getter, node1.name), "}}", "{{", (getter, node2.name), | |||||
| " | ", marker, (getter, node2.params[0].name), " = ", marker, | |||||
| (getter, node2.params[0].value), " | ", marker, | |||||
| (getter, node2.params[1].name), " = ", marker, | |||||
| (getter, node2.params[1].value), "}}"] | |||||
| self.assertEqual(valid, output) | |||||
| def test_name(self): | |||||
| """test getter/setter for the name attribute""" | |||||
| name = wraptext("foobar") | |||||
| node1 = Template(name) | |||||
| node2 = Template(name, [pgenh("1", "bar")]) | |||||
| self.assertIs(name, node1.name) | |||||
| self.assertIs(name, node2.name) | |||||
| node1.name = "asdf" | |||||
| node2.name = "téstïng" | |||||
| self.assertWikicodeEqual(wraptext("asdf"), node1.name) | |||||
| self.assertWikicodeEqual(wraptext("téstïng"), node2.name) | |||||
| def test_params(self): | |||||
| """test getter for the params attribute""" | |||||
| node1 = Template(wraptext("foobar")) | |||||
| plist = [pgenh("1", "bar"), pgens("abc", "def")] | |||||
| node2 = Template(wraptext("foo"), plist) | |||||
| self.assertEqual([], node1.params) | |||||
| self.assertIs(plist, node2.params) | |||||
| def test_has_param(self): | |||||
| """test Template.has_param()""" | |||||
| node1 = Template(wraptext("foobar")) | |||||
| node2 = Template(wraptext("foo"), | |||||
| [pgenh("1", "bar"), pgens("\nabc ", "def")]) | |||||
| node3 = Template(wraptext("foo"), | |||||
| [pgenh("1", "a"), pgens("b", "c"), pgens("1", "d")]) | |||||
| node4 = Template(wraptext("foo"), [pgenh("1", "a"), pgens("b", " ")]) | |||||
| self.assertFalse(node1.has_param("foobar")) | |||||
| self.assertTrue(node2.has_param(1)) | |||||
| self.assertTrue(node2.has_param("abc")) | |||||
| self.assertFalse(node2.has_param("def")) | |||||
| self.assertTrue(node3.has_param("1")) | |||||
| self.assertTrue(node3.has_param(" b ")) | |||||
| self.assertFalse(node4.has_param("b")) | |||||
| self.assertTrue(node3.has_param("b", False)) | |||||
| self.assertTrue(node4.has_param("b", False)) | |||||
| def test_get(self): | |||||
| """test Template.get()""" | |||||
| node1 = Template(wraptext("foobar")) | |||||
| node2p1 = pgenh("1", "bar") | |||||
| node2p2 = pgens("abc", "def") | |||||
| node2 = Template(wraptext("foo"), [node2p1, node2p2]) | |||||
| node3p1 = pgens("b", "c") | |||||
| node3p2 = pgens("1", "d") | |||||
| node3 = Template(wraptext("foo"), [pgenh("1", "a"), node3p1, node3p2]) | |||||
| node4p1 = pgens(" b", " ") | |||||
| node4 = Template(wraptext("foo"), [pgenh("1", "a"), node4p1]) | |||||
| self.assertRaises(ValueError, node1.get, "foobar") | |||||
| self.assertIs(node2p1, node2.get(1)) | |||||
| self.assertIs(node2p2, node2.get("abc")) | |||||
| self.assertRaises(ValueError, node2.get, "def") | |||||
| self.assertIs(node3p1, node3.get("b")) | |||||
| self.assertIs(node3p2, node3.get("1")) | |||||
| self.assertIs(node4p1, node4.get("b ")) | |||||
| def test_add(self): | |||||
| """test Template.add()""" | |||||
| node1 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")]) | |||||
| node2 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")]) | |||||
| node3 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")]) | |||||
| node4 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")]) | |||||
| node5 = Template(wraptext("a"), [pgens("b", "c"), | |||||
| pgens(" d ", "e")]) | |||||
| node6 = Template(wraptext("a"), [pgens("b", "c"), pgens("b", "d"), | |||||
| pgens("b", "e")]) | |||||
| node7 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")]) | |||||
| node8p = pgenh("1", "d") | |||||
| node8 = Template(wraptext("a"), [pgens("b", "c"), node8p]) | |||||
| node9 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "d")]) | |||||
| node10 = Template(wraptext("a"), [pgens("b", "c"), pgenh("1", "e")]) | |||||
| node11 = Template(wraptext("a"), [pgens("b", "c")]) | |||||
| node12 = Template(wraptext("a"), [pgens("b", "c")]) | |||||
| node13 = Template(wraptext("a"), [ | |||||
| pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]) | |||||
| node14 = Template(wraptext("a\n"), [ | |||||
| pgens("b ", "c\n"), pgens("d ", " e"), pgens("f ", "g\n"), | |||||
| pgens("h ", " i\n")]) | |||||
| node15 = Template(wraptext("a"), [ | |||||
| pgens("b ", " c\n"), pgens("\nd ", " e"), pgens("\nf ", "g ")]) | |||||
| node16 = Template(wraptext("a"), [ | |||||
| pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]) | |||||
| node17 = Template(wraptext("a"), [ | |||||
| pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]) | |||||
| node18 = Template(wraptext("a\n"), [ | |||||
| pgens("b ", "c\n"), pgens("d ", " e"), pgens("f ", "g\n"), | |||||
| pgens("h ", " i\n")]) | |||||
| node19 = Template(wraptext("a"), [ | |||||
| pgens("b ", " c\n"), pgens("\nd ", " e"), pgens("\nf ", "g ")]) | |||||
| node20 = Template(wraptext("a"), [ | |||||
| pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]) | |||||
| node21 = Template(wraptext("a"), [pgenh("1", "b")]) | |||||
| node22 = Template(wraptext("a"), [pgenh("1", "b")]) | |||||
| node23 = Template(wraptext("a"), [pgenh("1", "b")]) | |||||
| node24 = Template(wraptext("a"), [pgenh("1", "b"), pgenh("2", "c"), | |||||
| pgenh("3", "d"), pgenh("4", "e")]) | |||||
| node25 = Template(wraptext("a"), [pgenh("1", "b"), pgenh("2", "c"), | |||||
| pgens("4", "d"), pgens("5", "e")]) | |||||
| node26 = Template(wraptext("a"), [pgenh("1", "b"), pgenh("2", "c"), | |||||
| pgens("4", "d"), pgens("5", "e")]) | |||||
| node27 = Template(wraptext("a"), [pgenh("1", "b")]) | |||||
| node28 = Template(wraptext("a"), [pgenh("1", "b")]) | |||||
| node29 = Template(wraptext("a"), [pgens("b", "c")]) | |||||
| node30 = Template(wraptext("a"), [pgenh("1", "b")]) | |||||
| node31 = Template(wraptext("a"), [pgenh("1", "b")]) | |||||
| node32 = Template(wraptext("a"), [pgens("1", "b")]) | |||||
| node33 = Template(wraptext("a"), [ | |||||
| pgens("\nb ", " c"), pgens("\nd ", " e"), pgens("\nf ", " g")]) | |||||
| node34 = Template(wraptext("a\n"), [ | |||||
| pgens("b ", "c\n"), pgens("d ", " e"), pgens("f ", "g\n"), | |||||
| pgens("h ", " i\n")]) | |||||
| node35 = Template(wraptext("a"), [ | |||||
| pgens("b ", " c\n"), pgens("\nd ", " e"), pgens("\nf ", "g ")]) | |||||
| node36 = Template(wraptext("a"), [ | |||||
| pgens("\nb ", " c "), pgens("\nd ", " e "), pgens("\nf ", " g ")]) | |||||
| node37 = Template(wraptext("a"), [pgens("b", "c"), pgens("d", "e"), | |||||
| pgens("b", "f"), pgens("b", "h"), | |||||
| pgens("i", "j")]) | |||||
| node37 = Template(wraptext("a"), [pgens("b", "c"), pgens("d", "e"), | |||||
| pgens("b", "f"), pgens("b", "h"), | |||||
| pgens("i", "j")]) | |||||
| node38 = Template(wraptext("a"), [pgens("1", "b"), pgens("x", "y"), | |||||
| pgens("1", "c"), pgens("2", "d")]) | |||||
| node39 = Template(wraptext("a"), [pgens("1", "b"), pgens("x", "y"), | |||||
| pgenh("1", "c"), pgenh("2", "d")]) | |||||
| node40 = Template(wraptext("a"), [pgens("b", "c"), pgens("d", "e"), | |||||
| pgens("f", "g")]) | |||||
| node1.add("e", "f", showkey=True) | |||||
| node2.add(2, "g", showkey=False) | |||||
| node3.add("e", "foo|bar", showkey=True) | |||||
| node4.add("e", "f", showkey=True, before="b") | |||||
| node5.add("f", "g", showkey=True, before=" d ") | |||||
| node6.add("f", "g", showkey=True, before="b") | |||||
| self.assertRaises(ValueError, node7.add, "e", "f", showkey=True, | |||||
| before="q") | |||||
| node8.add("e", "f", showkey=True, before=node8p) | |||||
| node9.add("e", "f", showkey=True, before=pgenh("1", "d")) | |||||
| self.assertRaises(ValueError, node10.add, "e", "f", showkey=True, | |||||
| before=pgenh("1", "d")) | |||||
| node11.add("d", "foo=bar", showkey=True) | |||||
| node12.add("1", "foo=bar", showkey=False) | |||||
| node13.add("h", "i", showkey=True) | |||||
| node14.add("j", "k", showkey=True) | |||||
| node15.add("h", "i", showkey=True) | |||||
| node16.add("h", "i", showkey=True, preserve_spacing=False) | |||||
| node17.add("h", "i", showkey=False) | |||||
| node18.add("j", "k", showkey=False) | |||||
| node19.add("h", "i", showkey=False) | |||||
| node20.add("h", "i", showkey=False, preserve_spacing=False) | |||||
| node21.add("2", "c") | |||||
| node22.add("3", "c") | |||||
| node23.add("c", "d") | |||||
| node24.add("5", "f") | |||||
| node25.add("3", "f") | |||||
| node26.add("6", "f") | |||||
| node27.add("c", "foo=bar") | |||||
| node28.add("2", "foo=bar") | |||||
| node29.add("b", "d") | |||||
| node30.add("1", "foo=bar") | |||||
| node31.add("1", "foo=bar", showkey=True) | |||||
| node32.add("1", "foo=bar", showkey=False) | |||||
| node33.add("d", "foo") | |||||
| node34.add("f", "foo") | |||||
| node35.add("f", "foo") | |||||
| node36.add("d", "foo", preserve_spacing=False) | |||||
| node37.add("b", "k") | |||||
| node38.add("1", "e") | |||||
| node39.add("1", "e") | |||||
| node40.add("d", "h", before="b") | |||||
| self.assertEqual("{{a|b=c|d|e=f}}", node1) | |||||
| self.assertEqual("{{a|b=c|d|g}}", node2) | |||||
| self.assertEqual("{{a|b=c|d|e=foo|bar}}", node3) | |||||
| self.assertIsInstance(node3.params[2].value.get(1), HTMLEntity) | |||||
| self.assertEqual("{{a|e=f|b=c|d}}", node4) | |||||
| self.assertEqual("{{a|b=c|f=g| d =e}}", node5) | |||||
| self.assertEqual("{{a|b=c|b=d|f=g|b=e}}", node6) | |||||
| self.assertEqual("{{a|b=c|d}}", node7) | |||||
| self.assertEqual("{{a|b=c|e=f|d}}", node8) | |||||
| self.assertEqual("{{a|b=c|e=f|d}}", node9) | |||||
| self.assertEqual("{{a|b=c|e}}", node10) | |||||
| self.assertEqual("{{a|b=c|d=foo=bar}}", node11) | |||||
| self.assertEqual("{{a|b=c|foo=bar}}", node12) | |||||
| self.assertIsInstance(node12.params[1].value.get(1), HTMLEntity) | |||||
| self.assertEqual("{{a|\nb = c|\nd = e|\nf = g|\nh = i}}", node13) | |||||
| self.assertEqual("{{a\n|b =c\n|d = e|f =g\n|h = i\n|j =k\n}}", node14) | |||||
| self.assertEqual("{{a|b = c\n|\nd = e|\nf =g |h =i}}", node15) | |||||
| self.assertEqual("{{a|\nb = c|\nd = e|\nf = g|h=i}}", node16) | |||||
| self.assertEqual("{{a|\nb = c|\nd = e|\nf = g| i}}", node17) | |||||
| self.assertEqual("{{a\n|b =c\n|d = e|f =g\n|h = i\n|k\n}}", node18) | |||||
| self.assertEqual("{{a|b = c\n|\nd = e|\nf =g |i}}", node19) | |||||
| self.assertEqual("{{a|\nb = c|\nd = e|\nf = g|i}}", node20) | |||||
| self.assertEqual("{{a|b|c}}", node21) | |||||
| self.assertEqual("{{a|b|3=c}}", node22) | |||||
| self.assertEqual("{{a|b|c=d}}", node23) | |||||
| self.assertEqual("{{a|b|c|d|e|f}}", node24) | |||||
| self.assertEqual("{{a|b|c|4=d|5=e|f}}", node25) | |||||
| self.assertEqual("{{a|b|c|4=d|5=e|6=f}}", node26) | |||||
| self.assertEqual("{{a|b|c=foo=bar}}", node27) | |||||
| self.assertEqual("{{a|b|foo=bar}}", node28) | |||||
| self.assertIsInstance(node28.params[1].value.get(1), HTMLEntity) | |||||
| self.assertEqual("{{a|b=d}}", node29) | |||||
| self.assertEqual("{{a|foo=bar}}", node30) | |||||
| self.assertIsInstance(node30.params[0].value.get(1), HTMLEntity) | |||||
| self.assertEqual("{{a|1=foo=bar}}", node31) | |||||
| self.assertEqual("{{a|foo=bar}}", node32) | |||||
| self.assertIsInstance(node32.params[0].value.get(1), HTMLEntity) | |||||
| self.assertEqual("{{a|\nb = c|\nd = foo|\nf = g}}", node33) | |||||
| self.assertEqual("{{a\n|b =c\n|d = e|f =foo\n|h = i\n}}", node34) | |||||
| self.assertEqual("{{a|b = c\n|\nd = e|\nf =foo }}", node35) | |||||
| self.assertEqual("{{a|\nb = c |\nd =foo|\nf = g }}", node36) | |||||
| self.assertEqual("{{a|b=k|d=e|i=j}}", node37) | |||||
| self.assertEqual("{{a|1=e|x=y|2=d}}", node38) | |||||
| self.assertEqual("{{a|x=y|e|d}}", node39) | |||||
| self.assertEqual("{{a|b=c|d=h|f=g}}", node40) | |||||
| def test_remove(self): | |||||
| """test Template.remove()""" | |||||
| node1 = Template(wraptext("foobar")) | |||||
| node2 = Template(wraptext("foo"), [pgenh("1", "bar"), | |||||
| pgens("abc", "def")]) | |||||
| node3 = Template(wraptext("foo"), [pgenh("1", "bar"), | |||||
| pgens("abc", "def")]) | |||||
| node4 = Template(wraptext("foo"), [pgenh("1", "bar"), | |||||
| pgenh("2", "baz")]) | |||||
| node5 = Template(wraptext("foo"), [ | |||||
| pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]) | |||||
| node6 = Template(wraptext("foo"), [ | |||||
| pgens(" a", "b"), pgens("b", "c"), pgens("a ", "d")]) | |||||
| node7 = Template(wraptext("foo"), [ | |||||
| pgens("1 ", "a"), pgens(" 1", "b"), pgens("2", "c")]) | |||||
| node8 = Template(wraptext("foo"), [ | |||||
| pgens("1 ", "a"), pgens(" 1", "b"), pgens("2", "c")]) | |||||
| node9 = Template(wraptext("foo"), [ | |||||
| pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]) | |||||
| node10 = Template(wraptext("foo"), [ | |||||
| pgens("1 ", "a"), pgenh("1", "b"), pgenh("2", "c")]) | |||||
| node2.remove("1") | |||||
| node2.remove("abc") | |||||
| node3.remove(1, keep_field=True) | |||||
| node3.remove("abc", keep_field=True) | |||||
| node4.remove("1", keep_field=False) | |||||
| node5.remove("a", keep_field=False) | |||||
| node6.remove("a", keep_field=True) | |||||
| node7.remove(1, keep_field=True) | |||||
| node8.remove(1, keep_field=False) | |||||
| node9.remove(1, keep_field=True) | |||||
| node10.remove(1, keep_field=False) | |||||
| self.assertRaises(ValueError, node1.remove, 1) | |||||
| self.assertRaises(ValueError, node1.remove, "a") | |||||
| self.assertRaises(ValueError, node2.remove, "1") | |||||
| self.assertEqual("{{foo}}", node2) | |||||
| self.assertEqual("{{foo||abc=}}", node3) | |||||
| self.assertEqual("{{foo||baz}}", node4) | |||||
| self.assertEqual("{{foo|b=c}}", node5) | |||||
| self.assertEqual("{{foo| a=|b=c}}", node6) | |||||
| self.assertEqual("{{foo|1 =|2=c}}", node7) | |||||
| self.assertEqual("{{foo|2=c}}", node8) | |||||
| self.assertEqual("{{foo||c}}", node9) | |||||
| self.assertEqual("{{foo||c}}", node10) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||
| @@ -0,0 +1,75 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import Text | |||||
| class TestText(unittest.TestCase): | |||||
| """Test cases for the Text node.""" | |||||
| def test_unicode(self): | |||||
| """test Text.__unicode__()""" | |||||
| node = Text("foobar") | |||||
| self.assertEqual("foobar", str(node)) | |||||
| node2 = Text("fóóbar") | |||||
| self.assertEqual("fóóbar", str(node2)) | |||||
| def test_iternodes(self): | |||||
| """test Text.__iternodes__()""" | |||||
| node = Text("foobar") | |||||
| gen = node.__iternodes__(None) | |||||
| self.assertEqual((None, node), next(gen)) | |||||
| self.assertRaises(StopIteration, next, gen) | |||||
| def test_strip(self): | |||||
| """test Text.__strip__()""" | |||||
| node = Text("foobar") | |||||
| for a in (True, False): | |||||
| for b in (True, False): | |||||
| self.assertIs(node, node.__strip__(a, b)) | |||||
| def test_showtree(self): | |||||
| """test Text.__showtree__()""" | |||||
| output = [] | |||||
| node1 = Text("foobar") | |||||
| node2 = Text("fóóbar") | |||||
| node3 = Text("𐌲𐌿𐍄") | |||||
| node1.__showtree__(output.append, None, None) | |||||
| node2.__showtree__(output.append, None, None) | |||||
| node3.__showtree__(output.append, None, None) | |||||
| res = ["foobar", r"f\xf3\xf3bar", "\\U00010332\\U0001033f\\U00010344"] | |||||
| self.assertEqual(res, output) | |||||
| def test_value(self): | |||||
| """test getter/setter for the value attribute""" | |||||
| node = Text("foobar") | |||||
| self.assertEqual("foobar", node.value) | |||||
| self.assertIsInstance(node.value, str) | |||||
| node.value = "héhéhé" | |||||
| self.assertEqual("héhéhé", node.value) | |||||
| self.assertIsInstance(node.value, str) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||
| @@ -24,33 +24,28 @@ from __future__ import unicode_literals | |||||
| import unittest | import unittest | ||||
| from mwparserfromhell.nodes import Template, Text | from mwparserfromhell.nodes import Template, Text | ||||
| from mwparserfromhell.smart_list import SmartList | |||||
| from mwparserfromhell.utils import parse_anything | from mwparserfromhell.utils import parse_anything | ||||
| from mwparserfromhell.wikicode import Wikicode | |||||
| from ._test_tree_equality import TreeEqualityTestCase | |||||
| from ._test_tree_equality import TreeEqualityTestCase, wrap, wraptext | |||||
| class TestUtils(TreeEqualityTestCase): | class TestUtils(TreeEqualityTestCase): | ||||
| """Tests for the utils module, which provides parse_anything().""" | """Tests for the utils module, which provides parse_anything().""" | ||||
| def test_parse_anything_valid(self): | def test_parse_anything_valid(self): | ||||
| """tests for valid input to utils.parse_anything()""" | """tests for valid input to utils.parse_anything()""" | ||||
| wrap = lambda L: Wikicode(SmartList(L)) | |||||
| textify = lambda L: wrap([Text(item) for item in L]) | |||||
| tests = [ | tests = [ | ||||
| (wrap([Text("foobar")]), textify(["foobar"])), | |||||
| (Template(wrap([Text("spam")])), | |||||
| wrap([Template(textify(["spam"]))])), | |||||
| ("fóóbar", textify(["fóóbar"])), | |||||
| (b"foob\xc3\xa1r", textify(["foobár"])), | |||||
| (123, textify(["123"])), | |||||
| (True, textify(["True"])), | |||||
| (wraptext("foobar"), wraptext("foobar")), | |||||
| (Template(wraptext("spam")), wrap([Template(wraptext("spam"))])), | |||||
| ("fóóbar", wraptext("fóóbar")), | |||||
| (b"foob\xc3\xa1r", wraptext("foobár")), | |||||
| (123, wraptext("123")), | |||||
| (True, wraptext("True")), | |||||
| (None, wrap([])), | (None, wrap([])), | ||||
| ([Text("foo"), Text("bar"), Text("baz")], | ([Text("foo"), Text("bar"), Text("baz")], | ||||
| textify(["foo", "bar", "baz"])), | |||||
| ([wrap([Text("foo")]), Text("bar"), "baz", 123, 456], | |||||
| textify(["foo", "bar", "baz", "123", "456"])), | |||||
| ([[[([[((("foo",),),)], "bar"],)]]], textify(["foo", "bar"])) | |||||
| wraptext("foo", "bar", "baz")), | |||||
| ([wraptext("foo"), Text("bar"), "baz", 123, 456], | |||||
| wraptext("foo", "bar", "baz", "123", "456")), | |||||
| ([[[([[((("foo",),),)], "bar"],)]]], wraptext("foo", "bar")) | |||||
| ] | ] | ||||
| for test, valid in tests: | for test, valid in tests: | ||||
| self.assertWikicodeEqual(valid, parse_anything(test)) | self.assertWikicodeEqual(valid, parse_anything(test)) | ||||
| @@ -0,0 +1,107 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| # | |||||
| # Copyright (C) 2012-2013 Ben Kurtovic <ben.kurtovic@verizon.net> | |||||
| # | |||||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
| # of this software and associated documentation files (the "Software"), to deal | |||||
| # in the Software without restriction, including without limitation the rights | |||||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
| # copies of the Software, and to permit persons to whom the Software is | |||||
| # furnished to do so, subject to the following conditions: | |||||
| # | |||||
| # The above copyright notice and this permission notice shall be included in | |||||
| # all copies or substantial portions of the Software. | |||||
| # | |||||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
| # SOFTWARE. | |||||
| from __future__ import unicode_literals | |||||
| import unittest | |||||
| from mwparserfromhell.compat import str | |||||
| from mwparserfromhell.nodes import Text, Wikilink | |||||
| from ._test_tree_equality import TreeEqualityTestCase, getnodes, wrap, wraptext | |||||
| class TestWikilink(TreeEqualityTestCase): | |||||
| """Test cases for the Wikilink node.""" | |||||
| def test_unicode(self): | |||||
| """test Wikilink.__unicode__()""" | |||||
| node = Wikilink(wraptext("foobar")) | |||||
| self.assertEqual("[[foobar]]", str(node)) | |||||
| node2 = Wikilink(wraptext("foo"), wraptext("bar")) | |||||
| self.assertEqual("[[foo|bar]]", str(node2)) | |||||
| def test_iternodes(self): | |||||
| """test Wikilink.__iternodes__()""" | |||||
| node1n1 = Text("foobar") | |||||
| node2n1, node2n2, node2n3 = Text("foo"), Text("bar"), Text("baz") | |||||
| node1 = Wikilink(wrap([node1n1])) | |||||
| node2 = Wikilink(wrap([node2n1]), wrap([node2n2, node2n3])) | |||||
| gen1 = node1.__iternodes__(getnodes) | |||||
| gen2 = node2.__iternodes__(getnodes) | |||||
| self.assertEqual((None, node1), next(gen1)) | |||||
| self.assertEqual((None, node2), next(gen2)) | |||||
| self.assertEqual((node1.title, node1n1), next(gen1)) | |||||
| self.assertEqual((node2.title, node2n1), next(gen2)) | |||||
| self.assertEqual((node2.text, node2n2), next(gen2)) | |||||
| self.assertEqual((node2.text, node2n3), next(gen2)) | |||||
| self.assertRaises(StopIteration, next, gen1) | |||||
| self.assertRaises(StopIteration, next, gen2) | |||||
| def test_strip(self): | |||||
| """test Wikilink.__strip__()""" | |||||
| node = Wikilink(wraptext("foobar")) | |||||
| node2 = Wikilink(wraptext("foo"), wraptext("bar")) | |||||
| for a in (True, False): | |||||
| for b in (True, False): | |||||
| self.assertEqual("foobar", node.__strip__(a, b)) | |||||
| self.assertEqual("bar", node2.__strip__(a, b)) | |||||
| def test_showtree(self): | |||||
| """test Wikilink.__showtree__()""" | |||||
| output = [] | |||||
| getter, marker = object(), object() | |||||
| get = lambda code: output.append((getter, code)) | |||||
| mark = lambda: output.append(marker) | |||||
| node1 = Wikilink(wraptext("foobar")) | |||||
| node2 = Wikilink(wraptext("foo"), wraptext("bar")) | |||||
| node1.__showtree__(output.append, get, mark) | |||||
| node2.__showtree__(output.append, get, mark) | |||||
| valid = [ | |||||
| "[[", (getter, node1.title), "]]", "[[", (getter, node2.title), | |||||
| " | ", marker, (getter, node2.text), "]]"] | |||||
| self.assertEqual(valid, output) | |||||
| def test_title(self): | |||||
| """test getter/setter for the title attribute""" | |||||
| title = wraptext("foobar") | |||||
| node1 = Wikilink(title) | |||||
| node2 = Wikilink(title, wraptext("baz")) | |||||
| self.assertIs(title, node1.title) | |||||
| self.assertIs(title, node2.title) | |||||
| node1.title = "héhehé" | |||||
| node2.title = "héhehé" | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node1.title) | |||||
| self.assertWikicodeEqual(wraptext("héhehé"), node2.title) | |||||
| def test_text(self): | |||||
| """test getter/setter for the text attribute""" | |||||
| text = wraptext("baz") | |||||
| node1 = Wikilink(wraptext("foobar")) | |||||
| node2 = Wikilink(wraptext("foobar"), text) | |||||
| self.assertIs(None, node1.text) | |||||
| self.assertIs(text, node2.text) | |||||
| node1.text = "buzz" | |||||
| node2.text = None | |||||
| self.assertWikicodeEqual(wraptext("buzz"), node1.text) | |||||
| self.assertIs(None, node2.text) | |||||
| if __name__ == "__main__": | |||||
| unittest.main(verbosity=2) | |||||