diff --git a/mwparserfromhell/nodes/html_entity.py b/mwparserfromhell/nodes/html_entity.py
index 5b7607c..b51bd92 100644
--- a/mwparserfromhell/nodes/html_entity.py
+++ b/mwparserfromhell/nodes/html_entity.py
@@ -23,7 +23,7 @@
from __future__ import unicode_literals
from . import Node
-from ..compat import htmlentities, str
+from ..compat import htmlentities, py3k, str
__all__ = ["HTMLEntity"]
@@ -63,28 +63,31 @@ class HTMLEntity(Node):
return self.normalize()
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
def value(self):
@@ -119,19 +122,47 @@ class HTMLEntity(Node):
@value.setter
def value(self, 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
@named.setter
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
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
def hex_char(self, newval):
@@ -142,8 +173,9 @@ class HTMLEntity(Node):
def normalize(self):
"""Return the unicode character represented by the HTML entity."""
+ chrfunc = chr if py3k else HTMLEntity._unichr
if self.named:
- return unichr(htmlentities.name2codepoint[self.value])
+ return chrfunc(htmlentities.name2codepoint[self.value])
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))
diff --git a/mwparserfromhell/nodes/template.py b/mwparserfromhell/nodes/template.py
index e34ba7a..3834d41 100644
--- a/mwparserfromhell/nodes/template.py
+++ b/mwparserfromhell/nodes/template.py
@@ -81,7 +81,7 @@ class Template(Node):
in parameter names or values so they are not mistaken for new
parameters.
"""
- replacement = HTMLEntity(value=ord(char))
+ replacement = str(HTMLEntity(value=ord(char)))
for node in code.filter_text(recursive=False):
if char in node:
code.replace(node, node.replace(char, replacement))
@@ -107,7 +107,7 @@ class Template(Node):
values = tuple(theories.values())
best = max(values)
confidence = float(best) / sum(values)
- if confidence > 0.75:
+ if confidence >= 0.75:
return tuple(theories.keys())[values.index(best)]
def _get_spacing_conventions(self, use_names):
@@ -142,9 +142,9 @@ class Template(Node):
return False
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."""
- if not param.showkey and not force_no_field:
+ if not param.showkey:
dependents = [not after.showkey for after in self.params[i+1:]]
if any(dependents):
return False
@@ -183,11 +183,10 @@ class Template(Node):
def get(self, 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)
for param in reversed(self.params):
@@ -195,20 +194,34 @@ class Template(Node):
return param
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*.
*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
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
- 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)
self._surface_escape(value, "|")
@@ -217,14 +230,17 @@ class Template(Node):
self.remove(name, keep_field=True)
existing = self.get(name)
if showkey is not None:
- if not showkey:
- self._surface_escape(value, "=")
existing.showkey = showkey
+ if not existing.showkey:
+ self._surface_escape(value, "=")
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]])
+ else:
+ existing.value = value
return existing
if showkey is None:
@@ -246,43 +262,38 @@ class Template(Node):
if not showkey:
self._surface_escape(value, "=")
- if not force_nonconformity:
+ if preserve_spacing:
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)
- 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)
- 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
- 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*.
If *keep_field* is ``True``, we will keep the parameter's name, but
blank its value. Otherwise, we will remove the parameter completely
*unless* other parameters are dependent on it (e.g. removing ``bar``
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)
removed = False
+ to_remove =[]
for i, param in enumerate(self.params):
if param.name.strip() == name:
if keep_field:
@@ -290,13 +301,15 @@ class Template(Node):
self._blank_param_value(param.value)
keep_field = False
else:
- self.params.remove(param)
+ to_remove.append(param)
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:
self._blank_param_value(param.value)
if not removed:
removed = True
if not removed:
raise ValueError(name)
+ for param in to_remove:
+ self.params.remove(param)
diff --git a/mwparserfromhell/nodes/wikilink.py b/mwparserfromhell/nodes/wikilink.py
index 6fea468..527e9bb 100644
--- a/mwparserfromhell/nodes/wikilink.py
+++ b/mwparserfromhell/nodes/wikilink.py
@@ -79,4 +79,7 @@ class Wikilink(Node):
@text.setter
def text(self, value):
- self._text = parse_anything(value)
+ if value is None:
+ self._text = None
+ else:
+ self._text = parse_anything(value)
diff --git a/mwparserfromhell/wikicode.py b/mwparserfromhell/wikicode.py
index 8d8ebe2..f2d9c89 100644
--- a/mwparserfromhell/wikicode.py
+++ b/mwparserfromhell/wikicode.py
@@ -88,13 +88,7 @@ class Wikicode(StringMixIn):
If *obj* is a ``Node``, the function will test whether they are the
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):
"""Return ``True`` if *obj* is inside of *nodes*, else ``False``.
diff --git a/tests/_test_tree_equality.py b/tests/_test_tree_equality.py
index 758a72e..52130ed 100644
--- a/tests/_test_tree_equality.py
+++ b/tests/_test_tree_equality.py
@@ -26,8 +26,21 @@ from unittest import TestCase
from mwparserfromhell.nodes import (Argument, Comment, Heading, HTMLEntity,
Tag, Template, Text, Wikilink)
from mwparserfromhell.nodes.extras import Attribute, Parameter
+from mwparserfromhell.smart_list import SmartList
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):
"""A base test case with support for comparing the equality of node trees.
diff --git a/tests/test_argument.py b/tests/test_argument.py
new file mode 100644
index 0000000..8191804
--- /dev/null
+++ b/tests/test_argument.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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)
diff --git a/tests/test_builder.py b/tests/test_builder.py
index 1e578ed..903d144 100644
--- a/tests/test_builder.py
+++ b/tests/test_builder.py
@@ -28,12 +28,8 @@ from mwparserfromhell.nodes import (Argument, Comment, Heading, HTMLEntity,
from mwparserfromhell.nodes.extras import Attribute, Parameter
from mwparserfromhell.parser import tokens
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):
"""Tests for the builder, which turns tokens into Wikicode objects."""
@@ -44,10 +40,10 @@ class TestBuilder(TreeEqualityTestCase):
def test_text(self):
"""tests for building Text nodes"""
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")],
- wrap([Text("spam"), Text("eggs")])),
+ wraptext("spam", "eggs")),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))
@@ -57,25 +53,24 @@ class TestBuilder(TreeEqualityTestCase):
tests = [
([tokens.TemplateOpen(), tokens.Text(text="foobar"),
tokens.TemplateClose()],
- wrap([Template(wrap([Text("foobar")]))])),
+ wrap([Template(wraptext("foobar"))])),
([tokens.TemplateOpen(), tokens.Text(text="spam"),
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.TemplateParamSeparator(), tokens.Text(text="bar"),
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.TemplateParamSeparator(), tokens.Text(text="bar"),
tokens.TemplateParamEquals(), tokens.Text(text="baz"),
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.TemplateParamSeparator(), tokens.Text(text="bar"),
@@ -86,14 +81,12 @@ class TestBuilder(TreeEqualityTestCase):
tokens.TemplateParamEquals(), tokens.Text(text="buff"),
tokens.TemplateParamSeparator(), tokens.Text(text="baff"),
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)])])),
]
for test, valid in tests:
@@ -104,23 +97,22 @@ class TestBuilder(TreeEqualityTestCase):
tests = [
([tokens.ArgumentOpen(), tokens.Text(text="foobar"),
tokens.ArgumentClose()],
- wrap([Argument(wrap([Text("foobar")]))])),
+ wrap([Argument(wraptext("foobar"))])),
([tokens.ArgumentOpen(), tokens.Text(text="spam"),
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.ArgumentSeparator(), tokens.Text(text="bar"),
tokens.ArgumentClose()],
- wrap([Argument(wrap([Text("foo")]), wrap([Text("bar")]))])),
+ wrap([Argument(wraptext("foo"), wraptext("bar"))])),
([tokens.ArgumentOpen(), tokens.Text(text="foo"),
tokens.Text(text="bar"), tokens.ArgumentSeparator(),
tokens.Text(text="baz"), tokens.Text(text="biz"),
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:
self.assertWikicodeEqual(valid, self.builder.build(test))
@@ -130,23 +122,22 @@ class TestBuilder(TreeEqualityTestCase):
tests = [
([tokens.WikilinkOpen(), tokens.Text(text="foobar"),
tokens.WikilinkClose()],
- wrap([Wikilink(wrap([Text("foobar")]))])),
+ wrap([Wikilink(wraptext("foobar"))])),
([tokens.WikilinkOpen(), tokens.Text(text="spam"),
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.WikilinkSeparator(), tokens.Text(text="bar"),
tokens.WikilinkClose()],
- wrap([Wikilink(wrap([Text("foo")]), wrap([Text("bar")]))])),
+ wrap([Wikilink(wraptext("foo"), wraptext("bar"))])),
([tokens.WikilinkOpen(), tokens.Text(text="foo"),
tokens.Text(text="bar"), tokens.WikilinkSeparator(),
tokens.Text(text="baz"), tokens.Text(text="biz"),
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:
self.assertWikicodeEqual(valid, self.builder.build(test))
@@ -176,11 +167,11 @@ class TestBuilder(TreeEqualityTestCase):
tests = [
([tokens.HeadingStart(level=2), tokens.Text(text="foobar"),
tokens.HeadingEnd()],
- wrap([Heading(wrap([Text("foobar")]), 2)])),
+ wrap([Heading(wraptext("foobar"), 2)])),
([tokens.HeadingStart(level=4), tokens.Text(text="spam"),
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:
self.assertWikicodeEqual(valid, self.builder.build(test))
@@ -190,11 +181,11 @@ class TestBuilder(TreeEqualityTestCase):
tests = [
([tokens.CommentStart(), tokens.Text(text="foobar"),
tokens.CommentEnd()],
- wrap([Comment(wrap([Text("foobar")]))])),
+ wrap([Comment(wraptext("foobar"))])),
([tokens.CommentStart(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.CommentEnd()],
- wrap([Comment(wrap([Text("spam"), Text("eggs")]))])),
+ wrap([Comment(wraptext("spam", "eggs"))])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))
@@ -218,10 +209,10 @@ class TestBuilder(TreeEqualityTestCase):
tokens.TemplateOpen(), tokens.Text(text="bin"),
tokens.TemplateClose(), tokens.TemplateClose()]
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)])])
self.assertWikicodeEqual(valid, self.builder.build(test))
@@ -247,14 +238,14 @@ class TestBuilder(TreeEqualityTestCase):
tokens.Text(text="nbsp"), tokens.HTMLEntityEnd(),
tokens.TemplateClose()]
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))
if __name__ == "__main__":
diff --git a/tests/test_comment.py b/tests/test_comment.py
new file mode 100644
index 0000000..44225a2
--- /dev/null
+++ b/tests/test_comment.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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("", 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([""], 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)
diff --git a/tests/test_heading.py b/tests/test_heading.py
new file mode 100644
index 0000000..7a65872
--- /dev/null
+++ b/tests/test_heading.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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)
diff --git a/tests/test_html_entity.py b/tests/test_html_entity.py
new file mode 100644
index 0000000..d38e5ec
--- /dev/null
+++ b/tests/test_html_entity.py
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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)
diff --git a/tests/test_parameter.py b/tests/test_parameter.py
new file mode 100644
index 0000000..4786e12
--- /dev/null
+++ b/tests/test_parameter.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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)
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 9d2c969..ec5f065 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -26,10 +26,8 @@ import unittest
from mwparserfromhell import parser
from mwparserfromhell.nodes import Template, Text, Wikilink
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
class TestParser(TreeEqualityTestCase):
@@ -45,18 +43,17 @@ class TestParser(TreeEqualityTestCase):
def test_parsing(self):
"""integration test for parsing overall"""
text = "this is text; {{this|is=a|template={{with|[[links]]|in}}it}}"
- wrap = lambda L: Wikicode(SmartList(L))
expected = wrap([
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),
- Parameter(wrap([Text("2")]),
- wrap([Text("in")]), showkey=False)
+ Parameter(wraptext("2"),
+ wraptext("in"), showkey=False)
]),
Text("it")
]))
diff --git a/tests/test_template.py b/tests/test_template.py
new file mode 100644
index 0000000..28592df
--- /dev/null
+++ b/tests/test_template.py
@@ -0,0 +1,364 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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)
diff --git a/tests/test_text.py b/tests/test_text.py
new file mode 100644
index 0000000..35ac340
--- /dev/null
+++ b/tests/test_text.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index c088530..80a0e5e 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -24,33 +24,28 @@ from __future__ import unicode_literals
import unittest
from mwparserfromhell.nodes import Template, Text
-from mwparserfromhell.smart_list import SmartList
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):
"""Tests for the utils module, which provides parse_anything()."""
def test_parse_anything_valid(self):
"""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 = [
- (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([])),
([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:
self.assertWikicodeEqual(valid, parse_anything(test))
diff --git a/tests/test_wikilink.py b/tests/test_wikilink.py
new file mode 100644
index 0000000..7851032
--- /dev/null
+++ b/tests/test_wikilink.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012-2013 Ben Kurtovic
+#
+# 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)