Browse Source

Port tests to use pytest

pytest is the preferred way to write and run unit tests these days and
it has a cleaner interface - so lets switch to it. The tokenizer tests
especially are much easier to read/understand.

This was mostly done with find/replace regexes and then cleaned up
manually.
tags/v0.6.1
Kunal Mehta 4 years ago
parent
commit
03181bcd8b
28 changed files with 1751 additions and 1871 deletions
  1. +2
    -2
      .travis.yml
  2. +2
    -2
      appveyor.yml
  3. +1
    -1
      setup.py
  4. +0
    -148
      tests/_test_tokenizer.py
  5. +26
    -28
      tests/_test_tree_equality.py
  6. +18
    -19
      tests/test_argument.py
  7. +29
    -29
      tests/test_attribute.py
  8. +336
    -343
      tests/test_builder.py
  9. +8
    -10
      tests/test_comment.py
  10. +0
    -46
      tests/test_ctokenizer.py
  11. +8
    -11
      tests/test_docs.py
  12. +28
    -29
      tests/test_external_link.py
  13. +19
    -17
      tests/test_heading.py
  14. +78
    -64
      tests/test_html_entity.py
  15. +12
    -15
      tests/test_parameter.py
  16. +13
    -21
      tests/test_parser.py
  17. +0
    -48
      tests/test_pytokenizer.py
  18. +0
    -35
      tests/test_roundtripping.py
  19. +195
    -194
      tests/test_smart_list.py
  20. +254
    -245
      tests/test_string_mixin.py
  21. +133
    -124
      tests/test_tag.py
  22. +129
    -123
      tests/test_template.py
  23. +12
    -14
      tests/test_text.py
  24. +134
    -0
      tests/test_tokenizer.py
  25. +36
    -39
      tests/test_tokens.py
  26. +24
    -27
      tests/test_utils.py
  27. +236
    -218
      tests/test_wikicode.py
  28. +18
    -19
      tests/test_wikilink.py

+ 2
- 2
.travis.yml View File

@@ -7,10 +7,10 @@ python:
- 3.7
- 3.8
install:
- pip install coveralls
- pip install coveralls pytest
- python setup.py develop
script:
- coverage run --source=mwparserfromhell -m unittest discover
- coverage run --source=mwparserfromhell -m pytest
after_success:
- coveralls
env:


+ 2
- 2
appveyor.yml View File

@@ -64,14 +64,14 @@ environment:

install:
- "%PIP% install --disable-pip-version-check --user --upgrade pip"
- "%PIP% install wheel twine"
- "%PIP% install wheel twine pytest"

build_script:
- "%SETUPPY% build"
- "%SETUPPY% develop --user"

test_script:
- "%PYEXE% -m unittest discover"
- "%PYEXE% -m pytest"

after_test:
- "%SETUPPY% bdist_wheel"


+ 1
- 1
setup.py View File

@@ -75,7 +75,7 @@ setup(
name = "mwparserfromhell",
packages = find_packages(exclude=("tests",)),
ext_modules = [tokenizer] if use_extension else [],
test_suite = "tests",
test_requires = ["pytest"],
version = __version__,
python_requires = ">= 3.4",
author = "Ben Kurtovic",


+ 0
- 148
tests/_test_tokenizer.py View File

@@ -1,148 +0,0 @@
#
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
#
# 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.

import codecs
from os import listdir, path
import sys
import warnings

from mwparserfromhell.parser import tokens
from mwparserfromhell.parser.builder import Builder

class _TestParseError(Exception):
"""Raised internally when a test could not be parsed."""
pass


class TokenizerTestCase:
"""A base test case for tokenizers, whose tests are loaded dynamically.

Subclassed along with unittest.TestCase to form TestPyTokenizer and
TestCTokenizer. Tests are loaded dynamically from files in the 'tokenizer'
directory.
"""

@staticmethod
def _build_test_method(funcname, data):
"""Create and return a method to be treated as a test case method.

*data* is a dict containing multiple keys: the *input* text to be
tokenized, the expected list of tokens as *output*, and an optional
*label* for the method's docstring.
"""
def inner(self):
if hasattr(self, "roundtrip"):
expected = data["input"]
actual = str(Builder().build(data["output"][:]))
else:
expected = data["output"]
actual = self.tokenizer().tokenize(data["input"])
self.assertEqual(expected, actual)

inner.__doc__ = data["label"]
return inner

@staticmethod
def _parse_test(test, data):
"""Parse an individual *test*, storing its info in *data*."""
for line in test.strip().splitlines():
if line.startswith("name:"):
data["name"] = line[len("name:"):].strip()
elif line.startswith("label:"):
data["label"] = line[len("label:"):].strip()
elif line.startswith("input:"):
raw = line[len("input:"):].strip()
if raw[0] == '"' and raw[-1] == '"':
raw = raw[1:-1]
raw = raw.encode("raw_unicode_escape")
data["input"] = raw.decode("unicode_escape")
elif line.startswith("output:"):
raw = line[len("output:"):].strip()
try:
data["output"] = eval(raw, vars(tokens))
except Exception as err:
raise _TestParseError(err)

@classmethod
def _load_tests(cls, filename, name, text, restrict=None):
"""Load all tests in *text* from the file *filename*."""
tests = text.split("\n---\n")
counter = 1
digits = len(str(len(tests)))
for test in tests:
data = {"name": None, "label": None, "input": None, "output": None}
try:
cls._parse_test(test, data)
except _TestParseError as err:
if data["name"]:
error = "Could not parse test '{0}' in '{1}':\n\t{2}"
warnings.warn(error.format(data["name"], filename, err))
else:
error = "Could not parse a test in '{0}':\n\t{1}"
warnings.warn(error.format(filename, err))
continue

if not data["name"]:
error = "A test in '{0}' was ignored because it lacked a name"
warnings.warn(error.format(filename))
continue
if data["input"] is None or data["output"] is None:
error = "Test '{}' in '{}' was ignored because it lacked an input or an output"
warnings.warn(error.format(data["name"], filename))
continue

number = str(counter).zfill(digits)
counter += 1
if restrict and data["name"] != restrict:
continue

fname = "test_{}{}_{}".format(name, number, data["name"])
meth = cls._build_test_method(fname, data)
setattr(cls, fname, meth)

@classmethod
def build(cls):
"""Load and install all tests from the 'tokenizer' directory."""
def load_file(filename, restrict=None):
with codecs.open(filename, "r", encoding="utf8") as fp:
text = fp.read()
name = path.split(filename)[1][:-len(extension)]
cls._load_tests(filename, name, text, restrict)

directory = path.join(path.dirname(__file__), "tokenizer")
extension = ".mwtest"
if len(sys.argv) > 2 and sys.argv[1] == "--use":
for name in sys.argv[2:]:
if "." in name:
name, test = name.split(".", 1)
else:
test = None
load_file(path.join(directory, name + extension), test)
sys.argv = [sys.argv[0]] # So unittest doesn't try to parse this
cls.skip_others = True
else:
for filename in listdir(directory):
if not filename.endswith(extension):
continue
load_file(path.join(directory, filename))
cls.skip_others = False

TokenizerTestCase.build()

+ 26
- 28
tests/_test_tree_equality.py View File

@@ -19,18 +19,16 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

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])

class TreeEqualityTestCase(TestCase):

class TreeEqualityTestCase:
"""A base test case with support for comparing the equality of node trees.

This adds a number of type equality functions, for Wikicode, Text,
@@ -51,7 +49,7 @@ class TreeEqualityTestCase(TestCase):
}
for nodetype in registry:
if isinstance(expected, nodetype):
self.assertIsInstance(actual, nodetype)
assert isinstance(actual, nodetype)
registry[nodetype](expected, actual)

def assertArgumentNodeEqual(self, expected, actual):
@@ -60,23 +58,23 @@ class TreeEqualityTestCase(TestCase):
if expected.default is not None:
self.assertWikicodeEqual(expected.default, actual.default)
else:
self.assertIs(None, actual.default)
assert actual.default is None

def assertCommentNodeEqual(self, expected, actual):
"""Assert that two Comment nodes have the same data."""
self.assertEqual(expected.contents, actual.contents)
assert expected.contents == actual.contents

def assertHeadingNodeEqual(self, expected, actual):
"""Assert that two Heading nodes have the same data."""
self.assertWikicodeEqual(expected.title, actual.title)
self.assertEqual(expected.level, actual.level)
assert expected.level == actual.level

def assertHTMLEntityNodeEqual(self, expected, actual):
"""Assert that two HTMLEntity nodes have the same data."""
self.assertEqual(expected.value, actual.value)
self.assertIs(expected.named, actual.named)
self.assertIs(expected.hexadecimal, actual.hexadecimal)
self.assertEqual(expected.hex_char, actual.hex_char)
assert expected.value == actual.value
assert expected.named is actual.named
assert expected.hexadecimal is actual.hexadecimal
assert expected.hex_char == actual.hex_char

def assertTagNodeEqual(self, expected, actual):
"""Assert that two Tag nodes have the same data."""
@@ -84,39 +82,39 @@ class TreeEqualityTestCase(TestCase):
if expected.contents is not None:
self.assertWikicodeEqual(expected.contents, actual.contents)
length = len(expected.attributes)
self.assertEqual(length, len(actual.attributes))
assert length == len(actual.attributes)
for i in range(length):
exp_attr = expected.attributes[i]
act_attr = actual.attributes[i]
self.assertWikicodeEqual(exp_attr.name, act_attr.name)
if exp_attr.value is not None:
self.assertWikicodeEqual(exp_attr.value, act_attr.value)
self.assertEqual(exp_attr.quotes, act_attr.quotes)
self.assertEqual(exp_attr.pad_first, act_attr.pad_first)
self.assertEqual(exp_attr.pad_before_eq, act_attr.pad_before_eq)
self.assertEqual(exp_attr.pad_after_eq, act_attr.pad_after_eq)
self.assertEqual(expected.wiki_markup, actual.wiki_markup)
self.assertIs(expected.self_closing, actual.self_closing)
self.assertIs(expected.invalid, actual.invalid)
self.assertIs(expected.implicit, actual.implicit)
self.assertEqual(expected.padding, actual.padding)
assert exp_attr.quotes == act_attr.quotes
assert exp_attr.pad_first == act_attr.pad_first
assert exp_attr.pad_before_eq == act_attr.pad_before_eq
assert exp_attr.pad_after_eq == act_attr.pad_after_eq
assert expected.wiki_markup == actual.wiki_markup
assert expected.self_closing is actual.self_closing
assert expected.invalid is actual.invalid
assert expected.implicit is actual.implicit
assert expected.padding == actual.padding
self.assertWikicodeEqual(expected.closing_tag, actual.closing_tag)

def assertTemplateNodeEqual(self, expected, actual):
"""Assert that two Template nodes have the same data."""
self.assertWikicodeEqual(expected.name, actual.name)
length = len(expected.params)
self.assertEqual(length, len(actual.params))
assert length == len(actual.params)
for i in range(length):
exp_param = expected.params[i]
act_param = actual.params[i]
self.assertWikicodeEqual(exp_param.name, act_param.name)
self.assertWikicodeEqual(exp_param.value, act_param.value)
self.assertIs(exp_param.showkey, act_param.showkey)
assert exp_param.showkey is act_param.showkey

def assertTextNodeEqual(self, expected, actual):
"""Assert that two Text nodes have the same data."""
self.assertEqual(expected.value, actual.value)
assert expected.value == actual.value

def assertWikilinkNodeEqual(self, expected, actual):
"""Assert that two Wikilink nodes have the same data."""
@@ -124,12 +122,12 @@ class TreeEqualityTestCase(TestCase):
if expected.text is not None:
self.assertWikicodeEqual(expected.text, actual.text)
else:
self.assertIs(None, actual.text)
assert None is actual.text

def assertWikicodeEqual(self, expected, actual):
"""Assert that two Wikicode objects have the same data."""
self.assertIsInstance(actual, Wikicode)
assert isinstance(actual, Wikicode)
length = len(expected.nodes)
self.assertEqual(length, len(actual.nodes))
assert length == len(actual.nodes)
for i in range(length):
self.assertNodeEqual(expected.get(i), actual.get(i))

+ 18
- 19
tests/test_argument.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Argument, Text

@@ -31,9 +31,9 @@ class TestArgument(TreeEqualityTestCase):
def test_unicode(self):
"""test Argument.__unicode__()"""
node = Argument(wraptext("foobar"))
self.assertEqual("{{{foobar}}}", str(node))
assert "{{{foobar}}}" == str(node)
node2 = Argument(wraptext("foo"), wraptext("bar"))
self.assertEqual("{{{foo|bar}}}", str(node2))
assert "{{{foo|bar}}}" == str(node2)

def test_children(self):
"""test Argument.__children__()"""
@@ -41,18 +41,20 @@ class TestArgument(TreeEqualityTestCase):
node2 = Argument(wraptext("foo"), wrap([Text("bar"), Text("baz")]))
gen1 = node1.__children__()
gen2 = node2.__children__()
self.assertIs(node1.name, next(gen1))
self.assertIs(node2.name, next(gen2))
self.assertIs(node2.default, next(gen2))
self.assertRaises(StopIteration, next, gen1)
self.assertRaises(StopIteration, next, gen2)
assert node1.name is next(gen1)
assert node2.name is next(gen2)
assert node2.default is next(gen2)
with pytest.raises(StopIteration):
next(gen1)
with pytest.raises(StopIteration):
next(gen2)

def test_strip(self):
"""test Argument.__strip__()"""
node1 = Argument(wraptext("foobar"))
node2 = Argument(wraptext("foo"), wraptext("bar"))
self.assertIs(None, node1.__strip__())
self.assertEqual("bar", node2.__strip__())
assert node1.__strip__() is None
assert "bar" == node2.__strip__()

def test_showtree(self):
"""test Argument.__showtree__()"""
@@ -67,15 +69,15 @@ class TestArgument(TreeEqualityTestCase):
valid = [
"{{{", (getter, node1.name), "}}}", "{{{", (getter, node2.name),
" | ", marker, (getter, node2.default), "}}}"]
self.assertEqual(valid, output)
assert 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)
assert name is node1.name
assert name is node2.name
node1.name = "héhehé"
node2.name = "héhehé"
self.assertWikicodeEqual(wraptext("héhehé"), node1.name)
@@ -86,12 +88,9 @@ class TestArgument(TreeEqualityTestCase):
default = wraptext("baz")
node1 = Argument(wraptext("foobar"))
node2 = Argument(wraptext("foobar"), default)
self.assertIs(None, node1.default)
self.assertIs(default, node2.default)
assert None is node1.default
assert default is 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)
assert None is node2.default

+ 29
- 29
tests/test_attribute.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Template
from mwparserfromhell.nodes.extras import Attribute
@@ -32,23 +32,23 @@ class TestAttribute(TreeEqualityTestCase):
def test_unicode(self):
"""test Attribute.__unicode__()"""
node = Attribute(wraptext("foo"))
self.assertEqual(" foo", str(node))
assert " foo" == str(node)
node2 = Attribute(wraptext("foo"), wraptext("bar"))
self.assertEqual(' foo="bar"', str(node2))
assert ' foo="bar"' == str(node2)
node3 = Attribute(wraptext("a"), wraptext("b"), '"', "", " ", " ")
self.assertEqual('a = "b"', str(node3))
assert 'a = "b"' == str(node3)
node4 = Attribute(wraptext("a"), wraptext("b"), "'", "", " ", " ")
self.assertEqual("a = 'b'", str(node4))
assert "a = 'b'" == str(node4)
node5 = Attribute(wraptext("a"), wraptext("b"), None, "", " ", " ")
self.assertEqual("a = b", str(node5))
assert "a = b" == str(node5)
node6 = Attribute(wraptext("a"), wrap([]), None, " ", "", " ")
self.assertEqual(" a= ", str(node6))
assert " a= " == str(node6)

def test_name(self):
"""test getter/setter for the name attribute"""
name = wraptext("id")
node = Attribute(name, wraptext("bar"))
self.assertIs(name, node.name)
assert name is node.name
node.name = "{{id}}"
self.assertWikicodeEqual(wrap([Template(wraptext("id"))]), node.name)

@@ -56,51 +56,51 @@ class TestAttribute(TreeEqualityTestCase):
"""test getter/setter for the value attribute"""
value = wraptext("foo")
node = Attribute(wraptext("id"), value)
self.assertIs(value, node.value)
assert value is node.value
node.value = "{{bar}}"
self.assertWikicodeEqual(wrap([Template(wraptext("bar"))]), node.value)
node.value = None
self.assertIs(None, node.value)
assert None is node.value
node2 = Attribute(wraptext("id"), wraptext("foo"), None)
node2.value = "foo bar baz"
self.assertWikicodeEqual(wraptext("foo bar baz"), node2.value)
self.assertEqual('"', node2.quotes)
assert '"' == node2.quotes
node2.value = 'foo "bar" baz'
self.assertWikicodeEqual(wraptext('foo "bar" baz'), node2.value)
self.assertEqual("'", node2.quotes)
assert "'" == node2.quotes
node2.value = "foo 'bar' baz"
self.assertWikicodeEqual(wraptext("foo 'bar' baz"), node2.value)
self.assertEqual('"', node2.quotes)
assert '"' == node2.quotes
node2.value = "fo\"o 'bar' b\"az"
self.assertWikicodeEqual(wraptext("fo\"o 'bar' b\"az"), node2.value)
self.assertEqual('"', node2.quotes)
assert '"' == node2.quotes

def test_quotes(self):
"""test getter/setter for the quotes attribute"""
node1 = Attribute(wraptext("id"), wraptext("foo"), None)
node2 = Attribute(wraptext("id"), wraptext("bar"))
node3 = Attribute(wraptext("id"), wraptext("foo bar baz"))
self.assertIs(None, node1.quotes)
self.assertEqual('"', node2.quotes)
assert None is node1.quotes
assert '"' == node2.quotes
node1.quotes = "'"
node2.quotes = None
self.assertEqual("'", node1.quotes)
self.assertIs(None, node2.quotes)
self.assertRaises(ValueError, setattr, node1, "quotes", "foobar")
self.assertRaises(ValueError, setattr, node3, "quotes", None)
self.assertRaises(ValueError, Attribute, wraptext("id"),
wraptext("foo bar baz"), None)
assert "'" == node1.quotes
assert None is node2.quotes
with pytest.raises(ValueError):
node1.__setattr__("quotes", "foobar")
with pytest.raises(ValueError):
node3.__setattr__("quotes", None)
with pytest.raises(ValueError):
Attribute(wraptext("id"), wraptext("foo bar baz"), None)

def test_padding(self):
"""test getter/setter for the padding attributes"""
for pad in ["pad_first", "pad_before_eq", "pad_after_eq"]:
node = Attribute(wraptext("id"), wraptext("foo"), **{pad: "\n"})
self.assertEqual("\n", getattr(node, pad))
assert "\n" == getattr(node, pad)
setattr(node, pad, " ")
self.assertEqual(" ", getattr(node, pad))
assert " " == getattr(node, pad)
setattr(node, pad, None)
self.assertEqual("", getattr(node, pad))
self.assertRaises(ValueError, setattr, node, pad, True)

if __name__ == "__main__":
unittest.main(verbosity=2)
assert "" == getattr(node, pad)
with pytest.raises(ValueError):
node.__setattr__(pad, True)

+ 336
- 343
tests/test_builder.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import (Argument, Comment, ExternalLink, Heading,
HTMLEntity, Tag, Template, Text, Wikilink)
@@ -32,336 +32,328 @@ from ._test_tree_equality import TreeEqualityTestCase, wrap, wraptext
class TestBuilder(TreeEqualityTestCase):
"""Tests for the builder, which turns tokens into Wikicode objects."""

def setUp(self):
self.builder = Builder()

def test_text(self):
@pytest.fixture()
def builder(self):
return Builder()

@pytest.mark.parametrize("test,valid", [
([tokens.Text(text="foobar")], wraptext("foobar")),
([tokens.Text(text="fóóbar")], wraptext("fóóbar")),
([tokens.Text(text="spam"), tokens.Text(text="eggs")],
wraptext("spam", "eggs")),
])
def test_text(self, builder, test, valid):
"""tests for building Text nodes"""
tests = [
([tokens.Text(text="foobar")], wraptext("foobar")),
([tokens.Text(text="fóóbar")], wraptext("fóóbar")),
([tokens.Text(text="spam"), tokens.Text(text="eggs")],
wraptext("spam", "eggs")),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_template(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
([tokens.TemplateOpen(), tokens.Text(text="foobar"),
tokens.TemplateClose()],
wrap([Template(wraptext("foobar"))])),

([tokens.TemplateOpen(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.TemplateClose()],
wrap([Template(wraptext("spam", "eggs"))])),

([tokens.TemplateOpen(), tokens.Text(text="foo"),
tokens.TemplateParamSeparator(), tokens.Text(text="bar"),
tokens.TemplateClose()],
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(wraptext("foo"), params=[
Parameter(wraptext("bar"), wraptext("baz"))])])),

([tokens.TemplateOpen(), tokens.TemplateParamSeparator(),
tokens.TemplateParamSeparator(), tokens.TemplateParamEquals(),
tokens.TemplateParamSeparator(), tokens.TemplateClose()],
wrap([Template(wrap([]), params=[
Parameter(wraptext("1"), wrap([]), showkey=False),
Parameter(wrap([]), wrap([]), showkey=True),
Parameter(wraptext("2"), wrap([]), showkey=False)])])),

([tokens.TemplateOpen(), tokens.Text(text="foo"),
tokens.TemplateParamSeparator(), tokens.Text(text="bar"),
tokens.TemplateParamEquals(), tokens.Text(text="baz"),
tokens.TemplateParamSeparator(), tokens.Text(text="biz"),
tokens.TemplateParamSeparator(), tokens.Text(text="buzz"),
tokens.TemplateParamSeparator(), tokens.Text(text="3"),
tokens.TemplateParamEquals(), tokens.Text(text="buff"),
tokens.TemplateParamSeparator(), tokens.Text(text="baff"),
tokens.TemplateClose()],
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)])])),
])
def test_template(self, builder, test, valid):
"""tests for building Template nodes"""
tests = [
([tokens.TemplateOpen(), tokens.Text(text="foobar"),
tokens.TemplateClose()],
wrap([Template(wraptext("foobar"))])),

([tokens.TemplateOpen(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.TemplateClose()],
wrap([Template(wraptext("spam", "eggs"))])),

([tokens.TemplateOpen(), tokens.Text(text="foo"),
tokens.TemplateParamSeparator(), tokens.Text(text="bar"),
tokens.TemplateClose()],
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(wraptext("foo"), params=[
Parameter(wraptext("bar"), wraptext("baz"))])])),

([tokens.TemplateOpen(), tokens.TemplateParamSeparator(),
tokens.TemplateParamSeparator(), tokens.TemplateParamEquals(),
tokens.TemplateParamSeparator(), tokens.TemplateClose()],
wrap([Template(wrap([]), params=[
Parameter(wraptext("1"), wrap([]), showkey=False),
Parameter(wrap([]), wrap([]), showkey=True),
Parameter(wraptext("2"), wrap([]), showkey=False)])])),

([tokens.TemplateOpen(), tokens.Text(text="foo"),
tokens.TemplateParamSeparator(), tokens.Text(text="bar"),
tokens.TemplateParamEquals(), tokens.Text(text="baz"),
tokens.TemplateParamSeparator(), tokens.Text(text="biz"),
tokens.TemplateParamSeparator(), tokens.Text(text="buzz"),
tokens.TemplateParamSeparator(), tokens.Text(text="3"),
tokens.TemplateParamEquals(), tokens.Text(text="buff"),
tokens.TemplateParamSeparator(), tokens.Text(text="baff"),
tokens.TemplateClose()],
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:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_argument(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
([tokens.ArgumentOpen(), tokens.Text(text="foobar"),
tokens.ArgumentClose()],
wrap([Argument(wraptext("foobar"))])),

([tokens.ArgumentOpen(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.ArgumentClose()],
wrap([Argument(wraptext("spam", "eggs"))])),

([tokens.ArgumentOpen(), tokens.Text(text="foo"),
tokens.ArgumentSeparator(), tokens.Text(text="bar"),
tokens.ArgumentClose()],
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(wraptext("foo", "bar"), wraptext("baz", "biz"))])),
])
def test_argument(self, builder, test, valid):
"""tests for building Argument nodes"""
tests = [
([tokens.ArgumentOpen(), tokens.Text(text="foobar"),
tokens.ArgumentClose()],
wrap([Argument(wraptext("foobar"))])),

([tokens.ArgumentOpen(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.ArgumentClose()],
wrap([Argument(wraptext("spam", "eggs"))])),

([tokens.ArgumentOpen(), tokens.Text(text="foo"),
tokens.ArgumentSeparator(), tokens.Text(text="bar"),
tokens.ArgumentClose()],
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(wraptext("foo", "bar"), wraptext("baz", "biz"))])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_wikilink(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
([tokens.WikilinkOpen(), tokens.Text(text="foobar"),
tokens.WikilinkClose()],
wrap([Wikilink(wraptext("foobar"))])),

([tokens.WikilinkOpen(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.WikilinkClose()],
wrap([Wikilink(wraptext("spam", "eggs"))])),

([tokens.WikilinkOpen(), tokens.Text(text="foo"),
tokens.WikilinkSeparator(), tokens.Text(text="bar"),
tokens.WikilinkClose()],
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(wraptext("foo", "bar"), wraptext("baz", "biz"))])),
])
def test_wikilink(self, builder, test, valid):
"""tests for building Wikilink nodes"""
tests = [
([tokens.WikilinkOpen(), tokens.Text(text="foobar"),
tokens.WikilinkClose()],
wrap([Wikilink(wraptext("foobar"))])),

([tokens.WikilinkOpen(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.WikilinkClose()],
wrap([Wikilink(wraptext("spam", "eggs"))])),

([tokens.WikilinkOpen(), tokens.Text(text="foo"),
tokens.WikilinkSeparator(), tokens.Text(text="bar"),
tokens.WikilinkClose()],
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(wraptext("foo", "bar"), wraptext("baz", "biz"))])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_external_link(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
([tokens.ExternalLinkOpen(brackets=False),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"),
brackets=False)])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"))])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkSeparator(), tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"), wrap([]))])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkSeparator(), tokens.Text(text="Example"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"),
wraptext("Example"))])),

([tokens.ExternalLinkOpen(brackets=False),
tokens.Text(text="http://example"), tokens.Text(text=".com/foo"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example", ".com/foo"),
brackets=False)])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example"), tokens.Text(text=".com/foo"),
tokens.ExternalLinkSeparator(), tokens.Text(text="Example"),
tokens.Text(text=" Web Page"), tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example", ".com/foo"),
wraptext("Example", " Web Page"))])),
])
def test_external_link(self, builder, test, valid):
"""tests for building ExternalLink nodes"""
tests = [
([tokens.ExternalLinkOpen(brackets=False),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"),
brackets=False)])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"))])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkSeparator(), tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"), wrap([]))])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example.com/"),
tokens.ExternalLinkSeparator(), tokens.Text(text="Example"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example.com/"),
wraptext("Example"))])),

([tokens.ExternalLinkOpen(brackets=False),
tokens.Text(text="http://example"), tokens.Text(text=".com/foo"),
tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example", ".com/foo"),
brackets=False)])),

([tokens.ExternalLinkOpen(brackets=True),
tokens.Text(text="http://example"), tokens.Text(text=".com/foo"),
tokens.ExternalLinkSeparator(), tokens.Text(text="Example"),
tokens.Text(text=" Web Page"), tokens.ExternalLinkClose()],
wrap([ExternalLink(wraptext("http://example", ".com/foo"),
wraptext("Example", " Web Page"))])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_html_entity(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
([tokens.HTMLEntityStart(), tokens.Text(text="nbsp"),
tokens.HTMLEntityEnd()],
wrap([HTMLEntity("nbsp", named=True, hexadecimal=False)])),

([tokens.HTMLEntityStart(), tokens.HTMLEntityNumeric(),
tokens.Text(text="107"), tokens.HTMLEntityEnd()],
wrap([HTMLEntity("107", named=False, hexadecimal=False)])),

([tokens.HTMLEntityStart(), tokens.HTMLEntityNumeric(),
tokens.HTMLEntityHex(char="X"), tokens.Text(text="6B"),
tokens.HTMLEntityEnd()],
wrap([HTMLEntity("6B", named=False, hexadecimal=True,
hex_char="X")])),
])
def test_html_entity(self, builder, test, valid):
"""tests for building HTMLEntity nodes"""
tests = [
([tokens.HTMLEntityStart(), tokens.Text(text="nbsp"),
tokens.HTMLEntityEnd()],
wrap([HTMLEntity("nbsp", named=True, hexadecimal=False)])),

([tokens.HTMLEntityStart(), tokens.HTMLEntityNumeric(),
tokens.Text(text="107"), tokens.HTMLEntityEnd()],
wrap([HTMLEntity("107", named=False, hexadecimal=False)])),

([tokens.HTMLEntityStart(), tokens.HTMLEntityNumeric(),
tokens.HTMLEntityHex(char="X"), tokens.Text(text="6B"),
tokens.HTMLEntityEnd()],
wrap([HTMLEntity("6B", named=False, hexadecimal=True,
hex_char="X")])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_heading(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
([tokens.HeadingStart(level=2), tokens.Text(text="foobar"),
tokens.HeadingEnd()],
wrap([Heading(wraptext("foobar"), 2)])),

([tokens.HeadingStart(level=4), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.HeadingEnd()],
wrap([Heading(wraptext("spam", "eggs"), 4)])),
])
def test_heading(self, builder, test, valid):
"""tests for building Heading nodes"""
tests = [
([tokens.HeadingStart(level=2), tokens.Text(text="foobar"),
tokens.HeadingEnd()],
wrap([Heading(wraptext("foobar"), 2)])),

([tokens.HeadingStart(level=4), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.HeadingEnd()],
wrap([Heading(wraptext("spam", "eggs"), 4)])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_comment(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
([tokens.CommentStart(), tokens.Text(text="foobar"),
tokens.CommentEnd()],
wrap([Comment("foobar")])),

([tokens.CommentStart(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.CommentEnd()],
wrap([Comment("spameggs")])),
])
def test_comment(self, builder, test, valid):
"""tests for building Comment nodes"""
tests = [
([tokens.CommentStart(), tokens.Text(text="foobar"),
tokens.CommentEnd()],
wrap([Comment("foobar")])),

([tokens.CommentStart(), tokens.Text(text="spam"),
tokens.Text(text="eggs"), tokens.CommentEnd()],
wrap([Comment("spameggs")])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_tag(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("test,valid", [
# <ref></ref>
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagCloseOpen(padding=""), tokens.TagOpenClose(),
tokens.Text(text="ref"), tokens.TagCloseClose()],
wrap([Tag(wraptext("ref"), wrap([]),
closing_tag=wraptext("ref"))])),

# <ref name></ref>
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="name"), tokens.TagCloseOpen(padding=""),
tokens.TagOpenClose(), tokens.Text(text="ref"),
tokens.TagCloseClose()],
wrap([Tag(wraptext("ref"), wrap([]),
attrs=[Attribute(wraptext("name"))])])),

# <ref name="abc" />
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="name"), tokens.TagAttrEquals(),
tokens.TagAttrQuote(char='"'), tokens.Text(text="abc"),
tokens.TagCloseSelfclose(padding=" ")],
wrap([Tag(wraptext("ref"),
attrs=[Attribute(wraptext("name"), wraptext("abc"))],
self_closing=True, padding=" ")])),

# <br/>
([tokens.TagOpenOpen(), tokens.Text(text="br"),
tokens.TagCloseSelfclose(padding="")],
wrap([Tag(wraptext("br"), self_closing=True)])),

# <li>
([tokens.TagOpenOpen(), tokens.Text(text="li"),
tokens.TagCloseSelfclose(padding="", implicit=True)],
wrap([Tag(wraptext("li"), self_closing=True, implicit=True)])),

# </br>
([tokens.TagOpenOpen(invalid=True), tokens.Text(text="br"),
tokens.TagCloseSelfclose(padding="", implicit=True)],
wrap([Tag(wraptext("br"), self_closing=True, invalid=True,
implicit=True)])),

# </br/>
([tokens.TagOpenOpen(invalid=True), tokens.Text(text="br"),
tokens.TagCloseSelfclose(padding="")],
wrap([Tag(wraptext("br"), self_closing=True, invalid=True)])),

# <ref name={{abc}} foo="bar {{baz}}" abc={{de}}f ghi=j{{k}}{{l}}
# mno = '{{p}} [[q]] {{r}}'>[[Source]]</ref>
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="name"), tokens.TagAttrEquals(),
tokens.TemplateOpen(), tokens.Text(text="abc"),
tokens.TemplateClose(),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="foo"), tokens.TagAttrEquals(),
tokens.TagAttrQuote(char='"'), tokens.Text(text="bar "),
tokens.TemplateOpen(), tokens.Text(text="baz"),
tokens.TemplateClose(),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="abc"), tokens.TagAttrEquals(),
tokens.TemplateOpen(), tokens.Text(text="de"),
tokens.TemplateClose(), tokens.Text(text="f"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="ghi"), tokens.TagAttrEquals(),
tokens.Text(text="j"), tokens.TemplateOpen(),
tokens.Text(text="k"), tokens.TemplateClose(),
tokens.TemplateOpen(), tokens.Text(text="l"),
tokens.TemplateClose(),
tokens.TagAttrStart(pad_first=" \n ", pad_before_eq=" ",
pad_after_eq=" "),
tokens.Text(text="mno"), tokens.TagAttrEquals(),
tokens.TagAttrQuote(char="'"), tokens.TemplateOpen(),
tokens.Text(text="p"), tokens.TemplateClose(),
tokens.Text(text=" "), tokens.WikilinkOpen(),
tokens.Text(text="q"), tokens.WikilinkClose(),
tokens.Text(text=" "), tokens.TemplateOpen(),
tokens.Text(text="r"), tokens.TemplateClose(),
tokens.TagCloseOpen(padding=""), tokens.WikilinkOpen(),
tokens.Text(text="Source"), tokens.WikilinkClose(),
tokens.TagOpenClose(), tokens.Text(text="ref"),
tokens.TagCloseClose()],
wrap([Tag(wraptext("ref"), wrap([Wikilink(wraptext("Source"))]), [
Attribute(wraptext("name"),
wrap([Template(wraptext("abc"))]), None),
Attribute(wraptext("foo"), wrap([Text("bar "),
Template(wraptext("baz"))]), pad_first=" "),
Attribute(wraptext("abc"), wrap([Template(wraptext("de")),
Text("f")]), None),
Attribute(wraptext("ghi"), wrap([Text("j"),
Template(wraptext("k")),
Template(wraptext("l"))]), None),
Attribute(wraptext("mno"), wrap([Template(wraptext("p")),
Text(" "), Wikilink(wraptext("q")), Text(" "),
Template(wraptext("r"))]), "'", " \n ", " ",
" ")])])),

# "''italic text''"
([tokens.TagOpenOpen(wiki_markup="''"), tokens.Text(text="i"),
tokens.TagCloseOpen(), tokens.Text(text="italic text"),
tokens.TagOpenClose(), tokens.Text(text="i"),
tokens.TagCloseClose()],
wrap([Tag(wraptext("i"), wraptext("italic text"),
wiki_markup="''")])),

# * bullet
([tokens.TagOpenOpen(wiki_markup="*"), tokens.Text(text="li"),
tokens.TagCloseSelfclose(), tokens.Text(text=" bullet")],
wrap([Tag(wraptext("li"), wiki_markup="*", self_closing=True),
Text(" bullet")])),
])
def test_tag(self, builder, test, valid):
"""tests for building Tag nodes"""
tests = [
# <ref></ref>
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagCloseOpen(padding=""), tokens.TagOpenClose(),
tokens.Text(text="ref"), tokens.TagCloseClose()],
wrap([Tag(wraptext("ref"), wrap([]),
closing_tag=wraptext("ref"))])),

# <ref name></ref>
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="name"), tokens.TagCloseOpen(padding=""),
tokens.TagOpenClose(), tokens.Text(text="ref"),
tokens.TagCloseClose()],
wrap([Tag(wraptext("ref"), wrap([]),
attrs=[Attribute(wraptext("name"))])])),

# <ref name="abc" />
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="name"), tokens.TagAttrEquals(),
tokens.TagAttrQuote(char='"'), tokens.Text(text="abc"),
tokens.TagCloseSelfclose(padding=" ")],
wrap([Tag(wraptext("ref"),
attrs=[Attribute(wraptext("name"), wraptext("abc"))],
self_closing=True, padding=" ")])),

# <br/>
([tokens.TagOpenOpen(), tokens.Text(text="br"),
tokens.TagCloseSelfclose(padding="")],
wrap([Tag(wraptext("br"), self_closing=True)])),

# <li>
([tokens.TagOpenOpen(), tokens.Text(text="li"),
tokens.TagCloseSelfclose(padding="", implicit=True)],
wrap([Tag(wraptext("li"), self_closing=True, implicit=True)])),

# </br>
([tokens.TagOpenOpen(invalid=True), tokens.Text(text="br"),
tokens.TagCloseSelfclose(padding="", implicit=True)],
wrap([Tag(wraptext("br"), self_closing=True, invalid=True,
implicit=True)])),

# </br/>
([tokens.TagOpenOpen(invalid=True), tokens.Text(text="br"),
tokens.TagCloseSelfclose(padding="")],
wrap([Tag(wraptext("br"), self_closing=True, invalid=True)])),

# <ref name={{abc}} foo="bar {{baz}}" abc={{de}}f ghi=j{{k}}{{l}}
# mno = '{{p}} [[q]] {{r}}'>[[Source]]</ref>
([tokens.TagOpenOpen(), tokens.Text(text="ref"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="name"), tokens.TagAttrEquals(),
tokens.TemplateOpen(), tokens.Text(text="abc"),
tokens.TemplateClose(),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="foo"), tokens.TagAttrEquals(),
tokens.TagAttrQuote(char='"'), tokens.Text(text="bar "),
tokens.TemplateOpen(), tokens.Text(text="baz"),
tokens.TemplateClose(),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="abc"), tokens.TagAttrEquals(),
tokens.TemplateOpen(), tokens.Text(text="de"),
tokens.TemplateClose(), tokens.Text(text="f"),
tokens.TagAttrStart(pad_first=" ", pad_before_eq="",
pad_after_eq=""),
tokens.Text(text="ghi"), tokens.TagAttrEquals(),
tokens.Text(text="j"), tokens.TemplateOpen(),
tokens.Text(text="k"), tokens.TemplateClose(),
tokens.TemplateOpen(), tokens.Text(text="l"),
tokens.TemplateClose(),
tokens.TagAttrStart(pad_first=" \n ", pad_before_eq=" ",
pad_after_eq=" "),
tokens.Text(text="mno"), tokens.TagAttrEquals(),
tokens.TagAttrQuote(char="'"), tokens.TemplateOpen(),
tokens.Text(text="p"), tokens.TemplateClose(),
tokens.Text(text=" "), tokens.WikilinkOpen(),
tokens.Text(text="q"), tokens.WikilinkClose(),
tokens.Text(text=" "), tokens.TemplateOpen(),
tokens.Text(text="r"), tokens.TemplateClose(),
tokens.TagCloseOpen(padding=""), tokens.WikilinkOpen(),
tokens.Text(text="Source"), tokens.WikilinkClose(),
tokens.TagOpenClose(), tokens.Text(text="ref"),
tokens.TagCloseClose()],
wrap([Tag(wraptext("ref"), wrap([Wikilink(wraptext("Source"))]), [
Attribute(wraptext("name"),
wrap([Template(wraptext("abc"))]), None),
Attribute(wraptext("foo"), wrap([Text("bar "),
Template(wraptext("baz"))]), pad_first=" "),
Attribute(wraptext("abc"), wrap([Template(wraptext("de")),
Text("f")]), None),
Attribute(wraptext("ghi"), wrap([Text("j"),
Template(wraptext("k")),
Template(wraptext("l"))]), None),
Attribute(wraptext("mno"), wrap([Template(wraptext("p")),
Text(" "), Wikilink(wraptext("q")), Text(" "),
Template(wraptext("r"))]), "'", " \n ", " ",
" ")])])),

# "''italic text''"
([tokens.TagOpenOpen(wiki_markup="''"), tokens.Text(text="i"),
tokens.TagCloseOpen(), tokens.Text(text="italic text"),
tokens.TagOpenClose(), tokens.Text(text="i"),
tokens.TagCloseClose()],
wrap([Tag(wraptext("i"), wraptext("italic text"),
wiki_markup="''")])),

# * bullet
([tokens.TagOpenOpen(wiki_markup="*"), tokens.Text(text="li"),
tokens.TagCloseSelfclose(), tokens.Text(text=" bullet")],
wrap([Tag(wraptext("li"), wiki_markup="*", self_closing=True),
Text(" bullet")])),
]
for test, valid in tests:
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_integration(self):
self.assertWikicodeEqual(valid, builder.build(test))

def test_integration(self, builder):
"""a test for building a combination of templates together"""
# {{{{{{{{foo}}bar|baz=biz}}buzz}}usr|{{bin}}}}
test = [tokens.TemplateOpen(), tokens.TemplateOpen(),
@@ -380,9 +372,9 @@ class TestBuilder(TreeEqualityTestCase):
wraptext("biz"))]), Text("buzz")])), Text("usr")]), params=[
Parameter(wraptext("1"), wrap([Template(wraptext("bin"))]),
showkey=False)])])
self.assertWikicodeEqual(valid, self.builder.build(test))
self.assertWikicodeEqual(valid, builder.build(test))

def test_integration2(self):
def test_integration2(self, builder):
"""an even more audacious test for building a horrible wikicode mess"""
# {{a|b|{{c|[[d]]{{{e}}}}}}}[[f|{{{g}}}<!--h-->]]{{i|j=&nbsp;}}
test = [tokens.TemplateOpen(), tokens.Text(text="a"),
@@ -412,23 +404,24 @@ class TestBuilder(TreeEqualityTestCase):
"g")), Comment("h")])), Template(wraptext("i"), params=[
Parameter(wraptext("j"), wrap([HTMLEntity("nbsp",
named=True)]))])])
self.assertWikicodeEqual(valid, self.builder.build(test))

def test_parser_errors(self):
self.assertWikicodeEqual(valid, builder.build(test))

@pytest.mark.parametrize("tokens", [
[tokens.TemplateOpen(), tokens.TemplateParamSeparator()],
[tokens.TemplateOpen()], [tokens.ArgumentOpen()],
[tokens.WikilinkOpen()], [tokens.ExternalLinkOpen()],
[tokens.HeadingStart()], [tokens.CommentStart()],
[tokens.TagOpenOpen(), tokens.TagAttrStart()],
[tokens.TagOpenOpen()]
])
def test_parser_errors(self, builder, tokens):
"""test whether ParserError gets thrown for bad input"""
missing_closes = [
[tokens.TemplateOpen(), tokens.TemplateParamSeparator()],
[tokens.TemplateOpen()], [tokens.ArgumentOpen()],
[tokens.WikilinkOpen()], [tokens.ExternalLinkOpen()],
[tokens.HeadingStart()], [tokens.CommentStart()],
[tokens.TagOpenOpen(), tokens.TagAttrStart()],
[tokens.TagOpenOpen()]
]

msg = r"_handle_token\(\) got unexpected TemplateClose"
self.assertRaisesRegex(ParserError, msg, self.builder.build, [tokens.TemplateClose()])
for test in missing_closes:
self.assertRaises(ParserError, self.builder.build, test)

if __name__ == "__main__":
unittest.main(verbosity=2)
with pytest.raises(ParserError):
builder.build(tokens)

def test_parser_errors_templateclose(self, builder):
with pytest.raises(
ParserError,
match=r"_handle_token\(\) got unexpected TemplateClose"
):
builder.build([tokens.TemplateClose()])

+ 8
- 10
tests/test_comment.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Comment

@@ -31,32 +31,30 @@ class TestComment(TreeEqualityTestCase):
def test_unicode(self):
"""test Comment.__unicode__()"""
node = Comment("foobar")
self.assertEqual("<!--foobar-->", str(node))
assert "<!--foobar-->" == str(node)

def test_children(self):
"""test Comment.__children__()"""
node = Comment("foobar")
gen = node.__children__()
self.assertRaises(StopIteration, next, gen)
with pytest.raises(StopIteration):
next(gen)

def test_strip(self):
"""test Comment.__strip__()"""
node = Comment("foobar")
self.assertIs(None, node.__strip__())
assert node.__strip__() is None

def test_showtree(self):
"""test Comment.__showtree__()"""
output = []
node = Comment("foobar")
node.__showtree__(output.append, None, None)
self.assertEqual(["<!--foobar-->"], output)
assert ["<!--foobar-->"] == output

def test_contents(self):
"""test getter/setter for the contents attribute"""
node = Comment("foobar")
self.assertEqual("foobar", node.contents)
assert "foobar" == node.contents
node.contents = "barfoo"
self.assertEqual("barfoo", node.contents)

if __name__ == "__main__":
unittest.main(verbosity=2)
assert "barfoo" == node.contents

+ 0
- 46
tests/test_ctokenizer.py View File

@@ -1,46 +0,0 @@
#
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
#
# 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.

import unittest

try:
from mwparserfromhell.parser._tokenizer import CTokenizer
except ImportError:
CTokenizer = None

from ._test_tokenizer import TokenizerTestCase

@unittest.skipUnless(CTokenizer, "C tokenizer not available")
class TestCTokenizer(TokenizerTestCase, unittest.TestCase):
"""Test cases for the C tokenizer."""

@classmethod
def setUpClass(cls):
cls.tokenizer = CTokenizer

if not TokenizerTestCase.skip_others:
def test_uses_c(self):
"""make sure the C tokenizer identifies as using a C extension"""
self.assertTrue(CTokenizer.USES_C)
self.assertTrue(CTokenizer().USES_C)

if __name__ == "__main__":
unittest.main(verbosity=2)

+ 8
- 11
tests/test_docs.py View File

@@ -22,13 +22,13 @@
import json
from io import StringIO
import os
import unittest
import pytest
from urllib.parse import urlencode
from urllib.request import urlopen

import mwparserfromhell

class TestDocs(unittest.TestCase):
class TestDocs:
"""Integration test cases for mwparserfromhell's documentation."""

def assertPrint(self, input, output):
@@ -36,7 +36,7 @@ class TestDocs(unittest.TestCase):
buff = StringIO()
print(input, end="", file=buff)
buff.seek(0)
self.assertEqual(output, buff.read())
assert output == buff.read()

def test_readme_1(self):
"""test a block of example code in the README"""
@@ -88,9 +88,9 @@ class TestDocs(unittest.TestCase):
text = str(code)
res = "{{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{bar-stub}}"
self.assertPrint(text, res)
self.assertEqual(text, code)
assert text == code

@unittest.skipIf("NOWEB" in os.environ, "web test disabled by environ var")
@pytest.mark.skipif("NOWEB" in os.environ, reason="web test disabled by environ var")
def test_readme_5(self):
"""test a block of example code in the README; includes a web call"""
url1 = "https://en.wikipedia.org/w/api.php"
@@ -109,16 +109,13 @@ class TestDocs(unittest.TestCase):
try:
raw = urlopen(url1, urlencode(data).encode("utf8")).read()
except OSError:
self.skipTest("cannot continue because of unsuccessful web call")
pytest.skip("cannot continue because of unsuccessful web call")
res = json.loads(raw.decode("utf8"))
revision = res["query"]["pages"][0]["revisions"][0]
text = revision["slots"]["main"]["content"]
try:
expected = urlopen(url2.format(title)).read().decode("utf8")
except OSError:
self.skipTest("cannot continue because of unsuccessful web call")
pytest.skip("cannot continue because of unsuccessful web call")
actual = mwparserfromhell.parse(text)
self.assertEqual(expected, actual)

if __name__ == "__main__":
unittest.main(verbosity=2)
assert expected == actual

+ 28
- 29
tests/test_external_link.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import ExternalLink, Text

@@ -31,14 +31,14 @@ class TestExternalLink(TreeEqualityTestCase):
def test_unicode(self):
"""test ExternalLink.__unicode__()"""
node = ExternalLink(wraptext("http://example.com/"), brackets=False)
self.assertEqual("http://example.com/", str(node))
assert "http://example.com/" == str(node)
node2 = ExternalLink(wraptext("http://example.com/"))
self.assertEqual("[http://example.com/]", str(node2))
assert "[http://example.com/]" == str(node2)
node3 = ExternalLink(wraptext("http://example.com/"), wrap([]))
self.assertEqual("[http://example.com/ ]", str(node3))
assert "[http://example.com/ ]" == str(node3)
node4 = ExternalLink(wraptext("http://example.com/"),
wraptext("Example Web Page"))
self.assertEqual("[http://example.com/ Example Web Page]", str(node4))
assert "[http://example.com/ Example Web Page]" == str(node4)

def test_children(self):
"""test ExternalLink.__children__()"""
@@ -47,11 +47,13 @@ class TestExternalLink(TreeEqualityTestCase):
wrap([Text("Example"), Text("Page")]))
gen1 = node1.__children__()
gen2 = node2.__children__()
self.assertEqual(node1.url, next(gen1))
self.assertEqual(node2.url, next(gen2))
self.assertEqual(node2.title, next(gen2))
self.assertRaises(StopIteration, next, gen1)
self.assertRaises(StopIteration, next, gen2)
assert node1.url == next(gen1)
assert node2.url == next(gen2)
assert node2.title == next(gen2)
with pytest.raises(StopIteration):
next(gen1)
with pytest.raises(StopIteration):
next(gen2)

def test_strip(self):
"""test ExternalLink.__strip__()"""
@@ -60,10 +62,10 @@ class TestExternalLink(TreeEqualityTestCase):
node3 = ExternalLink(wraptext("http://example.com"), wrap([]))
node4 = ExternalLink(wraptext("http://example.com"), wraptext("Link"))

self.assertEqual("http://example.com", node1.__strip__())
self.assertEqual(None, node2.__strip__())
self.assertEqual(None, node3.__strip__())
self.assertEqual("Link", node4.__strip__())
assert "http://example.com" == node1.__strip__()
assert node2.__strip__() is None
assert node3.__strip__() is None
assert "Link" == node4.__strip__()

def test_showtree(self):
"""test ExternalLink.__showtree__()"""
@@ -78,15 +80,15 @@ class TestExternalLink(TreeEqualityTestCase):
valid = [
(getter, node1.url), "[", (getter, node2.url),
(getter, node2.title), "]"]
self.assertEqual(valid, output)
assert valid == output

def test_url(self):
"""test getter/setter for the url attribute"""
url = wraptext("http://example.com/")
node1 = ExternalLink(url, brackets=False)
node2 = ExternalLink(url, wraptext("Example"))
self.assertIs(url, node1.url)
self.assertIs(url, node2.url)
assert url is node1.url
assert url is node2.url
node1.url = "mailto:héhehé@spam.com"
node2.url = "mailto:héhehé@spam.com"
self.assertWikicodeEqual(wraptext("mailto:héhehé@spam.com"), node1.url)
@@ -97,10 +99,10 @@ class TestExternalLink(TreeEqualityTestCase):
title = wraptext("Example!")
node1 = ExternalLink(wraptext("http://example.com/"), brackets=False)
node2 = ExternalLink(wraptext("http://example.com/"), title)
self.assertIs(None, node1.title)
self.assertIs(title, node2.title)
assert None is node1.title
assert title is node2.title
node2.title = None
self.assertIs(None, node2.title)
assert None is node2.title
node2.title = "My Website"
self.assertWikicodeEqual(wraptext("My Website"), node2.title)

@@ -108,14 +110,11 @@ class TestExternalLink(TreeEqualityTestCase):
"""test getter/setter for the brackets attribute"""
node1 = ExternalLink(wraptext("http://example.com/"), brackets=False)
node2 = ExternalLink(wraptext("http://example.com/"), wraptext("Link"))
self.assertFalse(node1.brackets)
self.assertTrue(node2.brackets)
assert node1.brackets is False
assert node2.brackets is True
node1.brackets = True
node2.brackets = False
self.assertTrue(node1.brackets)
self.assertFalse(node2.brackets)
self.assertEqual("[http://example.com/]", str(node1))
self.assertEqual("http://example.com/", str(node2))

if __name__ == "__main__":
unittest.main(verbosity=2)
assert node1.brackets is True
assert node2.brackets is False
assert "[http://example.com/]" == str(node1)
assert "http://example.com/" == str(node2)

+ 19
- 17
tests/test_heading.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Heading, Text

@@ -31,21 +31,22 @@ class TestHeading(TreeEqualityTestCase):
def test_unicode(self):
"""test Heading.__unicode__()"""
node = Heading(wraptext("foobar"), 2)
self.assertEqual("==foobar==", str(node))
assert "==foobar==" == str(node)
node2 = Heading(wraptext(" zzz "), 5)
self.assertEqual("===== zzz =====", str(node2))
assert "===== zzz =====" == str(node2)

def test_children(self):
"""test Heading.__children__()"""
node = Heading(wrap([Text("foo"), Text("bar")]), 3)
gen = node.__children__()
self.assertEqual(node.title, next(gen))
self.assertRaises(StopIteration, next, gen)
assert node.title == next(gen)
with pytest.raises(StopIteration):
next(gen)

def test_strip(self):
"""test Heading.__strip__()"""
node = Heading(wraptext("foobar"), 3)
self.assertEqual("foobar", node.__strip__())
assert "foobar" == node.__strip__()

def test_showtree(self):
"""test Heading.__showtree__()"""
@@ -58,26 +59,27 @@ class TestHeading(TreeEqualityTestCase):
node2.__showtree__(output.append, get, None)
valid = ["===", (getter, node1.title), "===",
"====", (getter, node2.title), "===="]
self.assertEqual(valid, output)
assert 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)
assert title is 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)
assert 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)
assert 5 == node.level
with pytest.raises(ValueError):
node.__setattr__("level", 0)
with pytest.raises(ValueError):
node.__setattr__("level", 7)
with pytest.raises(ValueError):
node.__setattr__("level", "abc")
with pytest.raises(ValueError):
node.__setattr__("level", False)

+ 78
- 64
tests/test_html_entity.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import HTMLEntity

@@ -34,16 +34,17 @@ class TestHTMLEntity(TreeEqualityTestCase):
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("&nbsp;", str(node1))
self.assertEqual("&#107;", str(node2))
self.assertEqual("&#x6b;", str(node3))
self.assertEqual("&#X6C;", str(node4))
assert "&nbsp;" == str(node1)
assert "&#107;" == str(node2)
assert "&#x6b;" == str(node3)
assert "&#X6C;" == str(node4)

def test_children(self):
"""test HTMLEntity.__children__()"""
node = HTMLEntity("nbsp", named=True, hexadecimal=False)
gen = node.__children__()
self.assertRaises(StopIteration, next, gen)
with pytest.raises(StopIteration):
next(gen)

def test_strip(self):
"""test HTMLEntity.__strip__()"""
@@ -51,12 +52,12 @@ class TestHTMLEntity(TreeEqualityTestCase):
node2 = HTMLEntity("107", named=False, hexadecimal=False)
node3 = HTMLEntity("e9", named=False, hexadecimal=True)

self.assertEqual("\xa0", node1.__strip__(normalize=True))
self.assertEqual("&nbsp;", node1.__strip__(normalize=False))
self.assertEqual("k", node2.__strip__(normalize=True))
self.assertEqual("&#107;", node2.__strip__(normalize=False))
self.assertEqual("é", node3.__strip__(normalize=True))
self.assertEqual("&#xe9;", node3.__strip__(normalize=False))
assert "\xa0" == node1.__strip__(normalize=True)
assert "&nbsp;" == node1.__strip__(normalize=False)
assert "k" == node2.__strip__(normalize=True)
assert "&#107;" == node2.__strip__(normalize=False)
assert "é" == node3.__strip__(normalize=True)
assert "&#xe9;" == node3.__strip__(normalize=False)

def test_showtree(self):
"""test HTMLEntity.__showtree__()"""
@@ -68,88 +69,102 @@ class TestHTMLEntity(TreeEqualityTestCase):
node2.__showtree__(output.append, None, None)
node3.__showtree__(output.append, None, None)
res = ["&nbsp;", "&#107;", "&#xe9;"]
self.assertEqual(res, output)
assert 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)
assert "nbsp" == node1.value
assert "107" == node2.value
assert "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)
assert "ffa4" == node1.value
assert node1.named is False
assert node1.hexadecimal is True
assert "72" == node2.value
assert node2.named is False
assert node2.hexadecimal is False
assert "Sigma" == node3.value
assert node3.named is True
assert node3.hexadecimal is False

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")
self.assertRaises(ValueError, setattr, node1, "value", "12FFFF")
with pytest.raises(ValueError):
node3.__setattr__("value", "")
with pytest.raises(ValueError):
node3.__setattr__("value", "foobar")
with pytest.raises(ValueError):
node3.__setattr__("value", True)
with pytest.raises(ValueError):
node3.__setattr__("value", -1)
with pytest.raises(ValueError):
node1.__setattr__("value", 110000)
with pytest.raises(ValueError):
node1.__setattr__("value", "1114112")
with pytest.raises(ValueError):
node1.__setattr__("value", "12FFFF")

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)
assert node1.named is True
assert node2.named is False
assert node3.named is False
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)
assert node1.named is True
assert node2.named is False
assert node3.named is False
with pytest.raises(ValueError):
node1.__setattr__("named", False)
with pytest.raises(ValueError):
node2.__setattr__("named", True)
with pytest.raises(ValueError):
node3.__setattr__("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)
assert node1.hexadecimal is False
assert node2.hexadecimal is False
assert node3.hexadecimal is True
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)
assert node1.hexadecimal is False
assert node2.hexadecimal is True
assert node3.hexadecimal is False
with pytest.raises(ValueError):
node1.__setattr__("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)
assert "x" == node1.hex_char
assert "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)
assert "X" == node1.hex_char
assert "x" == node2.hex_char
with pytest.raises(ValueError):
node1.__setattr__("hex_char", 123)
with pytest.raises(ValueError):
node1.__setattr__("hex_char", "foobar")
with pytest.raises(ValueError):
node1.__setattr__("hex_char", True)

def test_normalize(self):
"""test getter/setter for the normalize attribute"""
@@ -159,12 +174,11 @@ class TestHTMLEntity(TreeEqualityTestCase):
node4 = HTMLEntity("1f648")
node5 = HTMLEntity("-2")
node6 = HTMLEntity("110000", named=False, hexadecimal=True)
self.assertEqual("\xa0", node1.normalize())
self.assertEqual("k", node2.normalize())
self.assertEqual("é", node3.normalize())
self.assertEqual("\U0001F648", node4.normalize())
self.assertRaises(ValueError, node5.normalize)
self.assertRaises(ValueError, node6.normalize)

if __name__ == "__main__":
unittest.main(verbosity=2)
assert "\xa0" == node1.normalize()
assert "k" == node2.normalize()
assert "é" == node3.normalize()
assert "\U0001F648" == node4.normalize()
with pytest.raises(ValueError):
node5.normalize()
with pytest.raises(ValueError):
node6.normalize()

+ 12
- 15
tests/test_parameter.py View File

@@ -19,9 +19,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Text
from mwparserfromhell.nodes.extras import Parameter

from ._test_tree_equality import TreeEqualityTestCase, wrap, wraptext
@@ -32,9 +31,9 @@ class TestParameter(TreeEqualityTestCase):
def test_unicode(self):
"""test Parameter.__unicode__()"""
node = Parameter(wraptext("1"), wraptext("foo"), showkey=False)
self.assertEqual("foo", str(node))
assert "foo" == str(node)
node2 = Parameter(wraptext("foo"), wraptext("bar"))
self.assertEqual("foo=bar", str(node2))
assert "foo=bar" == str(node2)

def test_name(self):
"""test getter/setter for the name attribute"""
@@ -42,8 +41,8 @@ class TestParameter(TreeEqualityTestCase):
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)
assert name1 is node1.name
assert name2 is node2.name
node1.name = "héhehé"
node2.name = "héhehé"
self.assertWikicodeEqual(wraptext("héhehé"), node1.name)
@@ -53,7 +52,7 @@ class TestParameter(TreeEqualityTestCase):
"""test getter/setter for the value attribute"""
value = wraptext("bar")
node = Parameter(wraptext("foo"), value)
self.assertIs(value, node.value)
assert value is node.value
node.value = "héhehé"
self.assertWikicodeEqual(wraptext("héhehé"), node.value)

@@ -61,13 +60,11 @@ class TestParameter(TreeEqualityTestCase):
"""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)
assert node1.showkey is False
assert node2.showkey is True
node1.showkey = True
self.assertTrue(node1.showkey)
assert node1.showkey is True
node1.showkey = ""
self.assertFalse(node1.showkey)
self.assertRaises(ValueError, setattr, node2, "showkey", False)

if __name__ == "__main__":
unittest.main(verbosity=2)
assert node1.showkey is False
with pytest.raises(ValueError):
node2.__setattr__("showkey", False)

+ 13
- 21
tests/test_parser.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell import parser
from mwparserfromhell.nodes import Tag, Template, Text, Wikilink
@@ -30,16 +30,19 @@ from ._test_tree_equality import TreeEqualityTestCase, wrap, wraptext
class TestParser(TreeEqualityTestCase):
"""Tests for the Parser class itself, which tokenizes and builds nodes."""

def test_use_c(self):
@pytest.fixture()
def pyparser(self):
"""make sure the correct tokenizer is used"""
restore = parser.use_c
if parser.use_c:
self.assertTrue(parser.Parser()._tokenizer.USES_C)
parser.use_c = False
self.assertFalse(parser.Parser()._tokenizer.USES_C)
yield
parser.use_c = restore

def test_parsing(self):
def test_use_c(self, pyparser):
assert parser.Parser()._tokenizer.USES_C is False

def test_parsing(self, pyparser):
"""integration test for parsing overall"""
text = "this is text; {{this|is=a|template={{with|[[links]]|in}}it}}"
expected = wrap([
@@ -61,26 +64,15 @@ class TestParser(TreeEqualityTestCase):
actual = parser.Parser().parse(text)
self.assertWikicodeEqual(expected, actual)

def test_skip_style_tags(self):
def test_skip_style_tags(self, pyparser):
"""test Parser.parse(skip_style_tags=True)"""
def test():
with_style = parser.Parser().parse(text, skip_style_tags=False)
without_style = parser.Parser().parse(text, skip_style_tags=True)
self.assertWikicodeEqual(a, with_style)
self.assertWikicodeEqual(b, without_style)

text = "This is an example with ''italics''!"
a = wrap([Text("This is an example with "),
Tag(wraptext("i"), wraptext("italics"), wiki_markup="''"),
Text("!")])
b = wraptext("This is an example with ''italics''!")

restore = parser.use_c
if parser.use_c:
test()
parser.use_c = False
test()
parser.use_c = restore

if __name__ == "__main__":
unittest.main(verbosity=2)
with_style = parser.Parser().parse(text, skip_style_tags=False)
without_style = parser.Parser().parse(text, skip_style_tags=True)
self.assertWikicodeEqual(a, with_style)
self.assertWikicodeEqual(b, without_style)

+ 0
- 48
tests/test_pytokenizer.py View File

@@ -1,48 +0,0 @@
#
# Copyright (C) 2012-2019 Ben Kurtovic <ben.kurtovic@gmail.com>
#
# 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.

import unittest

from mwparserfromhell.parser import contexts
from mwparserfromhell.parser.tokenizer import Tokenizer

from ._test_tokenizer import TokenizerTestCase

class TestPyTokenizer(TokenizerTestCase, unittest.TestCase):
"""Test cases for the Python tokenizer."""

@classmethod
def setUpClass(cls):
cls.tokenizer = Tokenizer

if not TokenizerTestCase.skip_others:
def test_uses_c(self):
"""make sure the Python tokenizer identifies as not using C"""
self.assertFalse(Tokenizer.USES_C)
self.assertFalse(Tokenizer().USES_C)

def test_describe_context(self):
self.assertEqual("", contexts.describe(0))
ctx = contexts.describe(contexts.TEMPLATE_PARAM_KEY|contexts.HAS_TEXT)
self.assertEqual("TEMPLATE_PARAM_KEY|HAS_TEXT", ctx)

if __name__ == "__main__":
unittest.main(verbosity=2)

+ 0
- 35
tests/test_roundtripping.py View File

@@ -1,35 +0,0 @@
#
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
#
# 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.

import unittest

from ._test_tokenizer import TokenizerTestCase

class TestRoundtripping(TokenizerTestCase, unittest.TestCase):
"""Test cases for roundtripping tokens back to wikitext."""

@classmethod
def setUpClass(cls):
cls.roundtrip = True


if __name__ == "__main__":
unittest.main(verbosity=2)

+ 195
- 194
tests/test_smart_list.py View File

@@ -19,104 +19,103 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.smart_list import SmartList
from mwparserfromhell.smart_list.ListProxy import _ListProxy


class TestSmartList(unittest.TestCase):
class TestSmartList:
"""Test cases for the SmartList class and its child, _ListProxy."""

def _test_get_set_del_item(self, builder):
"""Run tests on __get/set/delitem__ of a list built with *builder*."""
def assign(L, s1, s2, s3, val):
L[s1:s2:s3] = val
def delete(L, s1):
del L[s1]

list1 = builder([0, 1, 2, 3, "one", "two"])
list2 = builder(list(range(10)))

self.assertEqual(1, list1[1])
self.assertEqual("one", list1[-2])
self.assertEqual([2, 3], list1[2:4])
self.assertRaises(IndexError, lambda: list1[6])
self.assertRaises(IndexError, lambda: list1[-7])

self.assertEqual([0, 1, 2], list1[:3])
self.assertEqual([0, 1, 2, 3, "one", "two"], list1[:])
self.assertEqual([3, "one", "two"], list1[3:])
self.assertEqual([3, "one", "two"], list1[3:100])
self.assertEqual(["one", "two"], list1[-2:])
self.assertEqual([0, 1], list1[:-4])
self.assertEqual([], list1[6:])
self.assertEqual([], list1[4:2])

self.assertEqual([0, 2, "one"], list1[0:5:2])
self.assertEqual([0, 2], list1[0:-3:2])
self.assertEqual([0, 1, 2, 3, "one", "two"], list1[::])
self.assertEqual([2, 3, "one", "two"], list1[2::])
self.assertEqual([0, 1, 2, 3], list1[:4:])
self.assertEqual([2, 3], list1[2:4:])
self.assertEqual([0, 2, 4, 6, 8], list2[::2])
self.assertEqual([2, 5, 8], list2[2::3])
self.assertEqual([0, 3], list2[:6:3])
self.assertEqual([2, 5, 8], list2[-8:9:3])
self.assertEqual([], list2[100000:1000:-100])
assert 1 == list1[1]
assert "one" == list1[-2]
assert [2 == 3], list1[2:4]
with pytest.raises(IndexError):
list1[6]
with pytest.raises(IndexError):
list1[-7]

assert [0 == 1, 2], list1[:3]
assert [0 == 1, 2, 3, "one", "two"], list1[:]
assert [3 == "one", "two"], list1[3:]
assert [3 == "one", "two"], list1[3:100]
assert ["one" == "two"], list1[-2:]
assert [0 == 1], list1[:-4]
assert [] == list1[6:]
assert [] == list1[4:2]

assert [0 == 2, "one"], list1[0:5:2]
assert [0 == 2], list1[0:-3:2]
assert [0 == 1, 2, 3, "one", "two"], list1[::]
assert [2 == 3, "one", "two"], list1[2::]
assert [0 == 1, 2, 3], list1[:4:]
assert [2 == 3], list1[2:4:]
assert [0 == 2, 4, 6, 8], list2[::2]
assert [2 == 5, 8], list2[2::3]
assert [0 == 3], list2[:6:3]
assert [2 == 5, 8], list2[-8:9:3]
assert [] == list2[100000:1000:-100]

list1[3] = 100
self.assertEqual(100, list1[3])
assert 100 == list1[3]
list1[-3] = 101
self.assertEqual([0, 1, 2, 101, "one", "two"], list1)
assert [0 == 1, 2, 101, "one", "two"], list1
list1[5:] = [6, 7, 8]
self.assertEqual([6, 7, 8], list1[5:])
self.assertEqual([0, 1, 2, 101, "one", 6, 7, 8], list1)
assert [6 == 7, 8], list1[5:]
assert [0 == 1, 2, 101, "one", 6, 7, 8], list1
list1[2:4] = [-1, -2, -3, -4, -5]
self.assertEqual([0, 1, -1, -2, -3, -4, -5, "one", 6, 7, 8], list1)
assert [0 == 1, -1, -2, -3, -4, -5, "one", 6, 7, 8], list1
list1[0:-3] = [99]
self.assertEqual([99, 6, 7, 8], list1)
assert [99 == 6, 7, 8], list1
list2[0:6:2] = [100, 102, 104]
self.assertEqual([100, 1, 102, 3, 104, 5, 6, 7, 8, 9], list2)
assert [100 == 1, 102, 3, 104, 5, 6, 7, 8, 9], list2
list2[::3] = [200, 203, 206, 209]
self.assertEqual([200, 1, 102, 203, 104, 5, 206, 7, 8, 209], list2)
assert [200 == 1, 102, 203, 104, 5, 206, 7, 8, 209], list2
list2[::] = range(7)
self.assertEqual([0, 1, 2, 3, 4, 5, 6], list2)
self.assertRaises(ValueError, assign, list2, 0, 5, 2,
[100, 102, 104, 106])
with self.assertRaises(IndexError):
assert [0 == 1, 2, 3, 4, 5, 6], list2
with pytest.raises(ValueError):
list2[0:5:2] = [100, 102, 104, 106]
with pytest.raises(IndexError):
list2[7] = "foo"
with self.assertRaises(IndexError):
with pytest.raises(IndexError):
list2[-8] = "foo"

del list2[2]
self.assertEqual([0, 1, 3, 4, 5, 6], list2)
assert [0 == 1, 3, 4, 5, 6], list2
del list2[-3]
self.assertEqual([0, 1, 3, 5, 6], list2)
self.assertRaises(IndexError, delete, list2, 100)
self.assertRaises(IndexError, delete, list2, -6)
assert [0 == 1, 3, 5, 6], list2
with pytest.raises(IndexError):
del list2[100]
with pytest.raises(IndexError):
del list2[-6]
list2[:] = range(10)
del list2[3:6]
self.assertEqual([0, 1, 2, 6, 7, 8, 9], list2)
assert [0 == 1, 2, 6, 7, 8, 9], list2
del list2[-2:]
self.assertEqual([0, 1, 2, 6, 7], list2)
assert [0 == 1, 2, 6, 7], list2
del list2[:2]
self.assertEqual([2, 6, 7], list2)
assert [2 == 6, 7], list2
list2[:] = range(10)
del list2[2:8:2]
self.assertEqual([0, 1, 3, 5, 7, 8, 9], list2)
assert [0 == 1, 3, 5, 7, 8, 9], list2

def _test_add_radd_iadd(self, builder):
"""Run tests on __r/i/add__ of a list built with *builder*."""
list1 = builder(range(5))
list2 = builder(range(5, 10))
self.assertEqual([0, 1, 2, 3, 4, 5, 6], list1 + [5, 6])
self.assertEqual([0, 1, 2, 3, 4], list1)
self.assertEqual(list(range(10)), list1 + list2)
self.assertEqual([-2, -1, 0, 1, 2, 3, 4], [-2, -1] + list1)
self.assertEqual([0, 1, 2, 3, 4], list1)
assert [0 == 1, 2, 3, 4, 5, 6], list1 + [5, 6]
assert [0 == 1, 2, 3, 4], list1
assert list(range(10)) == list1 + list2
assert [-2 == -1, 0, 1, 2, 3, 4], [-2, -1] + list1
assert [0 == 1, 2, 3, 4], list1
list1 += ["foo", "bar", "baz"]
self.assertEqual([0, 1, 2, 3, 4, "foo", "bar", "baz"], list1)
assert [0 == 1, 2, 3, 4, "foo", "bar", "baz"], list1

def _test_other_magic_methods(self, builder):
"""Run tests on other magic methods of a list built with *builder*."""
@@ -125,80 +124,82 @@ class TestSmartList(unittest.TestCase):
list3 = builder([0, 2, 3, 4])
list4 = builder([0, 1, 2])

self.assertEqual("[0, 1, 2, 3, 'one', 'two']", str(list1))
self.assertEqual(b"\x00\x01\x02", bytes(list4))
self.assertEqual("[0, 1, 2, 3, 'one', 'two']", repr(list1))
assert "[0 == 1, 2, 3, 'one', 'two']", str(list1)
assert b"\x00\x01\x02" == bytes(list4)
assert "[0 == 1, 2, 3, 'one', 'two']", repr(list1)

self.assertLess(list1, list3)
self.assertLessEqual(list1, list3)
self.assertNotEqual(list1, list3)
self.assertNotEqual(list1, list3)
self.assertLessEqual(list1, list3)
self.assertLess(list1, list3)
assert list1 < list3
assert list1 <= list3
assert list1 != list3
assert list1 != list3
assert list1 <= list3
assert list1 < list3

other1 = [0, 2, 3, 4]
self.assertLess(list1, other1)
self.assertLessEqual(list1, other1)
self.assertNotEqual(list1, other1)
self.assertNotEqual(list1, other1)
self.assertLessEqual(list1, other1)
self.assertLess(list1, other1)
assert list1 < other1
assert list1 <= other1
assert list1 != other1
assert list1 != other1
assert list1 <= other1
assert list1 < other1

other2 = [0, 0, 1, 2]
self.assertGreaterEqual(list1, other2)
self.assertGreater(list1, other2)
self.assertNotEqual(list1, other2)
self.assertNotEqual(list1, other2)
self.assertGreater(list1, other2)
self.assertGreaterEqual(list1, other2)
assert list1 >= other2
assert list1 > other2
assert list1 != other2
assert list1 != other2
assert list1 > other2
assert list1 >= other2

other3 = [0, 1, 2, 3, "one", "two"]
self.assertGreaterEqual(list1, other3)
self.assertLessEqual(list1, other3)
self.assertEqual(list1, other3)
self.assertEqual(list1, other3)
self.assertLessEqual(list1, other3)
self.assertGreaterEqual(list1, other3)
assert list1 >= other3
assert list1 <= other3
assert list1 == other3
assert list1 == other3
assert list1 <= other3
assert list1 >= other3

self.assertTrue(bool(list1))
self.assertFalse(bool(list2))
assert bool(list1) is True
assert bool(list2) is False

self.assertEqual(6, len(list1))
self.assertEqual(0, len(list2))
assert 6 == len(list1)
assert 0 == len(list2)

out = []
for obj in list1:
out.append(obj)
self.assertEqual([0, 1, 2, 3, "one", "two"], out)
assert [0 == 1, 2, 3, "one", "two"], out

out = []
for ch in list2:
out.append(ch)
self.assertEqual([], out)
assert [] == out

gen1 = iter(list1)
out = []
for i in range(len(list1)):
out.append(next(gen1))
self.assertRaises(StopIteration, next, gen1)
self.assertEqual([0, 1, 2, 3, "one", "two"], out)
with pytest.raises(StopIteration):
next(gen1)
assert [0 == 1, 2, 3, "one", "two"], out
gen2 = iter(list2)
self.assertRaises(StopIteration, next, gen2)
with pytest.raises(StopIteration):
next(gen2)

self.assertEqual(["two", "one", 3, 2, 1, 0], list(reversed(list1)))
self.assertEqual([], list(reversed(list2)))
assert ["two" == "one", 3, 2, 1, 0], list(reversed(list1))
assert [] == list(reversed(list2))

self.assertIn("one", list1)
self.assertIn(3, list1)
self.assertNotIn(10, list1)
self.assertNotIn(0, list2)
assert "one" in list1
assert 3 in list1
assert 10 not in list1
assert 0 not in list2

self.assertEqual([], list2 * 5)
self.assertEqual([], 5 * list2)
self.assertEqual([0, 1, 2, 0, 1, 2, 0, 1, 2], list4 * 3)
self.assertEqual([0, 1, 2, 0, 1, 2, 0, 1, 2], 3 * list4)
assert [] == list2 * 5
assert [] == 5 * list2
assert [0 == 1, 2, 0, 1, 2, 0, 1, 2], list4 * 3
assert [0 == 1, 2, 0, 1, 2, 0, 1, 2], 3 * list4
list4 *= 2
self.assertEqual([0, 1, 2, 0, 1, 2], list4)
assert [0 == 1, 2, 0, 1, 2], list4

def _test_list_methods(self, builder):
"""Run tests on the public methods of a list built with *builder*."""
@@ -209,56 +210,59 @@ class TestSmartList(unittest.TestCase):
list1.append(5)
list1.append(1)
list1.append(2)
self.assertEqual([0, 1, 2, 3, 4, 5, 1, 2], list1)
assert [0 == 1, 2, 3, 4, 5, 1, 2], list1

self.assertEqual(0, list1.count(6))
self.assertEqual(2, list1.count(1))
assert 0 == list1.count(6)
assert 2 == list1.count(1)

list1.extend(range(5, 8))
self.assertEqual([0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1)
assert [0 == 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1

self.assertEqual(1, list1.index(1))
self.assertEqual(6, list1.index(1, 3))
self.assertEqual(6, list1.index(1, 3, 7))
self.assertRaises(ValueError, list1.index, 1, 3, 5)
assert 1 == list1.index(1)
assert 6 == list1.index(1, 3)
assert 6 == list1.index(1, 3, 7)
with pytest.raises(ValueError):
list1.index(1, 3, 5)

list1.insert(0, -1)
self.assertEqual([-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1)
assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 7], list1
list1.insert(-1, 6.5)
self.assertEqual([-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7], list1)
assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7], list1
list1.insert(13, 8)
self.assertEqual([-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7, 8], list1)

self.assertEqual(8, list1.pop())
self.assertEqual(7, list1.pop())
self.assertEqual([-1, 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5], list1)
self.assertEqual(-1, list1.pop(0))
self.assertEqual(5, list1.pop(5))
self.assertEqual(6.5, list1.pop(-1))
self.assertEqual([0, 1, 2, 3, 4, 1, 2, 5, 6], list1)
self.assertEqual("foo", list2.pop())
self.assertRaises(IndexError, list2.pop)
self.assertEqual([], list2)
assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5, 7, 8], list1

assert 8 == list1.pop()
assert 7 == list1.pop()
assert [-1 == 0, 1, 2, 3, 4, 5, 1, 2, 5, 6, 6.5], list1
assert -1 == list1.pop(0)
assert 5 == list1.pop(5)
assert 6.5 == list1.pop(-1)
assert [0 == 1, 2, 3, 4, 1, 2, 5, 6], list1
assert "foo" == list2.pop()
with pytest.raises(IndexError):
list2.pop()
assert [] == list2

list1.remove(6)
self.assertEqual([0, 1, 2, 3, 4, 1, 2, 5], list1)
assert [0 == 1, 2, 3, 4, 1, 2, 5], list1
list1.remove(1)
self.assertEqual([0, 2, 3, 4, 1, 2, 5], list1)
assert [0 == 2, 3, 4, 1, 2, 5], list1
list1.remove(1)
self.assertEqual([0, 2, 3, 4, 2, 5], list1)
self.assertRaises(ValueError, list1.remove, 1)
assert [0 == 2, 3, 4, 2, 5], list1
with pytest.raises(ValueError):
list1.remove(1)

list1.reverse()
self.assertEqual([5, 2, 4, 3, 2, 0], list1)
assert [5 == 2, 4, 3, 2, 0], list1

list1.sort()
self.assertEqual([0, 2, 2, 3, 4, 5], list1)
assert [0 == 2, 2, 3, 4, 5], list1
list1.sort(reverse=True)
self.assertEqual([5, 4, 3, 2, 2, 0], list1)
assert [5 == 4, 3, 2, 2, 0], list1
list3.sort(key=lambda i: i[1])
self.assertEqual([("d", 2), ("c", 3), ("a", 5), ("b", 8)], list3)
assert [("d", 2), ("c", 3), ("a", 5), ("b", 8)] == list3
list3.sort(key=lambda i: i[1], reverse=True)
self.assertEqual([("b", 8), ("a", 5), ("c", 3), ("d", 2)], list3)
assert [("b", 8), ("a", 5), ("c", 3), ("d", 2)] == list3

def _dispatch_test_for_children(self, meth):
"""Run a test method on various different types of children."""
@@ -275,18 +279,18 @@ class TestSmartList(unittest.TestCase):
expected = getattr(list, meth).__doc__
smartlist_doc = getattr(SmartList, meth).__doc__
listproxy_doc = getattr(_ListProxy, meth).__doc__
self.assertEqual(expected, smartlist_doc)
self.assertEqual(expected, listproxy_doc)
assert expected == smartlist_doc
assert expected == listproxy_doc

def test_doctest(self):
"""make sure the test embedded in SmartList's docstring passes"""
parent = SmartList([0, 1, 2, 3])
self.assertEqual([0, 1, 2, 3], parent)
assert [0 == 1, 2, 3], parent
child = parent[2:]
self.assertEqual([2, 3], child)
assert [2 == 3], child
child.append(4)
self.assertEqual([2, 3, 4], child)
self.assertEqual([0, 1, 2, 3, 4], parent)
assert [2 == 3, 4], child
assert [0 == 1, 2, 3, 4], parent

def test_parent_get_set_del(self):
"""make sure SmartList's getitem/setitem/delitem work"""
@@ -325,85 +329,82 @@ class TestSmartList(unittest.TestCase):
parent = SmartList([0, 1, 2, 3, 4, 5])
child1 = parent[2:]
child2 = parent[2:5]
self.assertEqual([0, 1, 2, 3, 4, 5], parent)
self.assertEqual([2, 3, 4, 5], child1)
self.assertEqual([2, 3, 4], child2)
self.assertEqual(2, len(parent._children))
assert [0 == 1, 2, 3, 4, 5], parent
assert [2 == 3, 4, 5], child1
assert [2 == 3, 4], child2
assert 2 == len(parent._children)

parent.append(6)
child1.append(7)
child2.append(4.5)
self.assertEqual([0, 1, 2, 3, 4, 4.5, 5, 6, 7], parent)
self.assertEqual([2, 3, 4, 4.5, 5, 6, 7], child1)
self.assertEqual([2, 3, 4, 4.5], child2)
assert [0 == 1, 2, 3, 4, 4.5, 5, 6, 7], parent
assert [2 == 3, 4, 4.5, 5, 6, 7], child1
assert [2 == 3, 4, 4.5], child2

parent.insert(0, -1)
parent.insert(4, 2.5)
parent.insert(10, 6.5)
self.assertEqual([-1, 0, 1, 2, 2.5, 3, 4, 4.5, 5, 6, 6.5, 7], parent)
self.assertEqual([2, 2.5, 3, 4, 4.5, 5, 6, 6.5, 7], child1)
self.assertEqual([2, 2.5, 3, 4, 4.5], child2)
assert [-1 == 0, 1, 2, 2.5, 3, 4, 4.5, 5, 6, 6.5, 7], parent
assert [2 == 2.5, 3, 4, 4.5, 5, 6, 6.5, 7], child1
assert [2 == 2.5, 3, 4, 4.5], child2

self.assertEqual(7, parent.pop())
self.assertEqual(6.5, child1.pop())
self.assertEqual(4.5, child2.pop())
self.assertEqual([-1, 0, 1, 2, 2.5, 3, 4, 5, 6], parent)
self.assertEqual([2, 2.5, 3, 4, 5, 6], child1)
self.assertEqual([2, 2.5, 3, 4], child2)
assert 7 == parent.pop()
assert 6.5 == child1.pop()
assert 4.5 == child2.pop()
assert [-1 == 0, 1, 2, 2.5, 3, 4, 5, 6], parent
assert [2 == 2.5, 3, 4, 5, 6], child1
assert [2 == 2.5, 3, 4], child2

parent.remove(-1)
child1.remove(2.5)
self.assertEqual([0, 1, 2, 3, 4, 5, 6], parent)
self.assertEqual([2, 3, 4, 5, 6], child1)
self.assertEqual([2, 3, 4], child2)
assert [0 == 1, 2, 3, 4, 5, 6], parent
assert [2 == 3, 4, 5, 6], child1
assert [2 == 3, 4], child2

self.assertEqual(0, parent.pop(0))
self.assertEqual([1, 2, 3, 4, 5, 6], parent)
self.assertEqual([2, 3, 4, 5, 6], child1)
self.assertEqual([2, 3, 4], child2)
assert 0 == parent.pop(0)
assert [1 == 2, 3, 4, 5, 6], parent
assert [2 == 3, 4, 5, 6], child1
assert [2 == 3, 4], child2

child2.reverse()
self.assertEqual([1, 4, 3, 2, 5, 6], parent)
self.assertEqual([4, 3, 2, 5, 6], child1)
self.assertEqual([4, 3, 2], child2)
assert [1 == 4, 3, 2, 5, 6], parent
assert [4 == 3, 2, 5, 6], child1
assert [4 == 3, 2], child2

parent.extend([7, 8])
child1.extend([8.1, 8.2])
child2.extend([1.9, 1.8])
self.assertEqual([1, 4, 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2], parent)
self.assertEqual([4, 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2], child1)
self.assertEqual([4, 3, 2, 1.9, 1.8], child2)
assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2], parent
assert [4 == 3, 2, 1.9, 1.8, 5, 6, 7, 8, 8.1, 8.2], child1
assert [4 == 3, 2, 1.9, 1.8], child2

child3 = parent[9:]
self.assertEqual([8, 8.1, 8.2], child3)
assert [8 == 8.1, 8.2], child3

del parent[8:]
self.assertEqual([1, 4, 3, 2, 1.9, 1.8, 5, 6], parent)
self.assertEqual([4, 3, 2, 1.9, 1.8, 5, 6], child1)
self.assertEqual([4, 3, 2, 1.9, 1.8], child2)
self.assertEqual([], child3)
self.assertEqual(0, len(child3))
assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6], parent
assert [4 == 3, 2, 1.9, 1.8, 5, 6], child1
assert [4 == 3, 2, 1.9, 1.8], child2
assert [] == child3
assert 0 == len(child3)

del child1
self.assertEqual([1, 4, 3, 2, 1.9, 1.8, 5, 6], parent)
self.assertEqual([4, 3, 2, 1.9, 1.8], child2)
self.assertEqual([], child3)
self.assertEqual(2, len(parent._children))
assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6], parent
assert [4 == 3, 2, 1.9, 1.8], child2
assert [] == child3
assert 2 == len(parent._children)

del child3
self.assertEqual([1, 4, 3, 2, 1.9, 1.8, 5, 6], parent)
self.assertEqual([4, 3, 2, 1.9, 1.8], child2)
self.assertEqual(1, len(parent._children))
assert [1 == 4, 3, 2, 1.9, 1.8, 5, 6], parent
assert [4 == 3, 2, 1.9, 1.8], child2
assert 1 == len(parent._children)

parent.remove(1.9)
parent.remove(1.8)
self.assertEqual([1, 4, 3, 2, 5, 6], parent)
self.assertEqual([4, 3, 2], child2)
assert [1 == 4, 3, 2, 5, 6], parent
assert [4 == 3, 2], child2

parent.reverse()
self.assertEqual([6, 5, 2, 3, 4, 1], parent)
self.assertEqual([4, 3, 2], child2)
self.assertEqual(0, len(parent._children))

if __name__ == "__main__":
unittest.main(verbosity=2)
assert [6 == 5, 2, 3, 4, 1], parent
assert [4 == 3, 2], child2
assert 0 == len(parent._children)

+ 254
- 245
tests/test_string_mixin.py View File

@@ -19,9 +19,9 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import pytest
from sys import getdefaultencoding
from types import GeneratorType
import unittest

from mwparserfromhell.string_mixin import StringMixIn

@@ -33,37 +33,35 @@ class _FakeString(StringMixIn):
return self._data


class TestStringMixIn(unittest.TestCase):
class TestStringMixIn:
"""Test cases for the StringMixIn class."""

def test_docs(self):
@pytest.mark.parametrize('method', [
"capitalize", "casefold", "center", "count", "encode", "endswith",
"expandtabs", "find", "format", "format_map", "index", "isalnum",
"isalpha", "isdecimal", "isdigit", "isidentifier", "islower",
"isnumeric", "isprintable", "isspace", "istitle", "isupper",
"join", "ljust", "lower", "lstrip", "maketrans", "partition",
"replace", "rfind", "rindex", "rjust", "rpartition", "rsplit",
"rstrip", "split", "splitlines", "startswith", "strip", "swapcase",
"title", "translate", "upper", "zfill"
])
def test_docs(self, method):
"""make sure the various methods of StringMixIn have docstrings"""
methods = [
"capitalize", "casefold", "center", "count", "encode", "endswith",
"expandtabs", "find", "format", "format_map", "index", "isalnum",
"isalpha", "isdecimal", "isdigit", "isidentifier", "islower",
"isnumeric", "isprintable", "isspace", "istitle", "isupper",
"join", "ljust", "lower", "lstrip", "maketrans", "partition",
"replace", "rfind", "rindex", "rjust", "rpartition", "rsplit",
"rstrip", "split", "splitlines", "startswith", "strip", "swapcase",
"title", "translate", "upper", "zfill"
]

for meth in methods:
expected = getattr("foo", meth).__doc__
actual = getattr(_FakeString("foo"), meth).__doc__
self.assertEqual(expected, actual)
expected = getattr("foo", method).__doc__
actual = getattr(_FakeString("foo"), method).__doc__
assert expected == actual

def test_types(self):
"""make sure StringMixIns convert to different types correctly"""
fstr = _FakeString("fake string")
self.assertEqual(str(fstr), "fake string")
self.assertEqual(bytes(fstr), b"fake string")
self.assertEqual(repr(fstr), "'fake string'")
assert str(fstr) == "fake string"
assert bytes(fstr) == b"fake string"
assert repr(fstr) == "'fake string'"

self.assertIsInstance(str(fstr), str)
self.assertIsInstance(bytes(fstr), bytes)
self.assertIsInstance(repr(fstr), str)
assert isinstance(str(fstr), str)
assert isinstance(bytes(fstr), bytes)
assert isinstance(repr(fstr), str)

def test_comparisons(self):
"""make sure comparison operators work"""
@@ -73,33 +71,33 @@ class TestStringMixIn(unittest.TestCase):
str4 = "this is a fake string"
str5 = "fake string, this is"

self.assertLessEqual(str1, str2)
self.assertGreaterEqual(str1, str2)
self.assertEqual(str1, str2)
self.assertEqual(str1, str2)
self.assertGreaterEqual(str1, str2)
self.assertLessEqual(str1, str2)
self.assertGreater(str1, str3)
self.assertGreaterEqual(str1, str3)
self.assertNotEqual(str1, str3)
self.assertNotEqual(str1, str3)
self.assertGreaterEqual(str1, str3)
self.assertGreater(str1, str3)
self.assertLessEqual(str1, str4)
self.assertGreaterEqual(str1, str4)
self.assertEqual(str1, str4)
self.assertEqual(str1, str4)
self.assertGreaterEqual(str1, str4)
self.assertLessEqual(str1, str4)
self.assertLessEqual(str5, str1)
self.assertLess(str5, str1)
self.assertNotEqual(str5, str1)
self.assertNotEqual(str5, str1)
self.assertLess(str5, str1)
self.assertLessEqual(str5, str1)
assert str1 <= str2
assert str1 >= str2
assert str1 == str2
assert str1 == str2
assert str1 >= str2
assert str1 <= str2
assert str1 > str3
assert str1 >= str3
assert str1 != str3
assert str1 != str3
assert str1 >= str3
assert str1 > str3
assert str1 <= str4
assert str1 >= str4
assert str1 == str4
assert str1 == str4
assert str1 >= str4
assert str1 <= str4
assert str5 <= str1
assert str5 < str1
assert str5 != str1
assert str5 != str1
assert str5 < str1
assert str5 <= str1

def test_other_magics(self):
"""test other magically implemented features, like len() and iter()"""
@@ -107,298 +105,309 @@ class TestStringMixIn(unittest.TestCase):
str2 = _FakeString("")
expected = ["f", "a", "k", "e", " ", "s", "t", "r", "i", "n", "g"]

self.assertTrue(str1)
self.assertFalse(str2)
self.assertEqual(11, len(str1))
self.assertEqual(0, len(str2))
assert bool(str1) is True
assert bool(str2) is False
assert 11 == len(str1)
assert 0 == len(str2)

out = []
for ch in str1:
out.append(ch)
self.assertEqual(expected, out)
assert expected == out

out = []
for ch in str2:
out.append(ch)
self.assertEqual([], out)
assert [] == out

gen1 = iter(str1)
gen2 = iter(str2)
self.assertIsInstance(gen1, GeneratorType)
self.assertIsInstance(gen2, GeneratorType)
assert isinstance(gen1, GeneratorType)
assert isinstance(gen2, GeneratorType)

out = []
for i in range(len(str1)):
out.append(next(gen1))
self.assertRaises(StopIteration, next, gen1)
self.assertEqual(expected, out)
self.assertRaises(StopIteration, next, gen2)

self.assertEqual("gnirts ekaf", "".join(list(reversed(str1))))
self.assertEqual([], list(reversed(str2)))

self.assertEqual("f", str1[0])
self.assertEqual(" ", str1[4])
self.assertEqual("g", str1[10])
self.assertEqual("n", str1[-2])
self.assertRaises(IndexError, lambda: str1[11])
self.assertRaises(IndexError, lambda: str2[0])

self.assertIn("k", str1)
self.assertIn("fake", str1)
self.assertIn("str", str1)
self.assertIn("", str1)
self.assertIn("", str2)
self.assertNotIn("real", str1)
self.assertNotIn("s", str2)
with pytest.raises(StopIteration):
next(gen1)
assert expected == out
with pytest.raises(StopIteration):
next(gen2)

assert "gnirts ekaf" == "".join(list(reversed(str1)))
assert [] == list(reversed(str2))

assert "f" == str1[0]
assert " " == str1[4]
assert "g" == str1[10]
assert "n" == str1[-2]
with pytest.raises(IndexError):
str1[11]
with pytest.raises(IndexError):
str2[0]

assert "k" in str1
assert "fake" in str1
assert "str" in str1
assert "" in str1
assert "" in str2
assert "real" not in str1
assert "s" not in str2

def test_other_methods(self):
"""test the remaining non-magic methods of StringMixIn"""
str1 = _FakeString("fake string")
self.assertEqual("Fake string", str1.capitalize())
assert "Fake string" == str1.capitalize()

self.assertEqual(" fake string ", str1.center(15))
self.assertEqual(" fake string ", str1.center(16))
self.assertEqual("qqfake stringqq", str1.center(15, "q"))
assert " fake string " == str1.center(15)
assert " fake string " == str1.center(16)
assert "qqfake stringqq" == str1.center(15, "q")

self.assertEqual(1, str1.count("e"))
self.assertEqual(0, str1.count("z"))
self.assertEqual(1, str1.count("r", 7))
self.assertEqual(0, str1.count("r", 8))
self.assertEqual(1, str1.count("r", 5, 9))
self.assertEqual(0, str1.count("r", 5, 7))
assert 1 == str1.count("e")
assert 0 == str1.count("z")
assert 1 == str1.count("r", 7)
assert 0 == str1.count("r", 8)
assert 1 == str1.count("r", 5, 9)
assert 0 == str1.count("r", 5, 7)

str3 = _FakeString("𐌲𐌿𐍄")
actual = b"\xF0\x90\x8C\xB2\xF0\x90\x8C\xBF\xF0\x90\x8D\x84"
self.assertEqual(b"fake string", str1.encode())
self.assertEqual(actual, str3.encode("utf-8"))
self.assertEqual(actual, str3.encode(encoding="utf-8"))
assert b"fake string" == str1.encode()
assert actual == str3.encode("utf-8")
assert actual == str3.encode(encoding="utf-8")
if getdefaultencoding() == "ascii":
self.assertRaises(UnicodeEncodeError, str3.encode)
with pytest.raises(UnicodeEncodeError):
str3.encode()
elif getdefaultencoding() == "utf-8":
self.assertEqual(actual, str3.encode())
self.assertRaises(UnicodeEncodeError, str3.encode, "ascii")
self.assertRaises(UnicodeEncodeError, str3.encode, "ascii", "strict")
assert actual == str3.encode()
with pytest.raises(UnicodeEncodeError):
str3.encode("ascii")
with pytest.raises(UnicodeEncodeError):
str3.encode("ascii", "strict")
if getdefaultencoding() == "ascii":
self.assertRaises(UnicodeEncodeError, str3.encode, errors="strict")
with pytest.raises(UnicodeEncodeError):
str3.encode("ascii", errors="strict")
elif getdefaultencoding() == "utf-8":
self.assertEqual(actual, str3.encode(errors="strict"))
self.assertEqual(b"", str3.encode("ascii", "ignore"))
assert actual == str3.encode(errors="strict")
assert b"" == str3.encode("ascii", "ignore")
if getdefaultencoding() == "ascii":
self.assertEqual(b"", str3.encode(errors="ignore"))
assert b"" == str3.encode(errors="ignore")
elif getdefaultencoding() == "utf-8":
self.assertEqual(actual, str3.encode(errors="ignore"))
assert actual == str3.encode(errors="ignore")

self.assertTrue(str1.endswith("ing"))
self.assertFalse(str1.endswith("ingh"))
assert str1.endswith("ing") is True
assert str1.endswith("ingh") is False

str4 = _FakeString("\tfoobar")
self.assertEqual("fake string", str1)
self.assertEqual(" foobar", str4.expandtabs())
self.assertEqual(" foobar", str4.expandtabs(4))
assert "fake string" == str1
assert " foobar" == str4.expandtabs()
assert " foobar" == str4.expandtabs(4)

self.assertEqual(3, str1.find("e"))
self.assertEqual(-1, str1.find("z"))
self.assertEqual(7, str1.find("r", 7))
self.assertEqual(-1, str1.find("r", 8))
self.assertEqual(7, str1.find("r", 5, 9))
self.assertEqual(-1, str1.find("r", 5, 7))
assert 3 == str1.find("e")
assert -1 == str1.find("z")
assert 7 == str1.find("r", 7)
assert -1 == str1.find("r", 8)
assert 7 == str1.find("r", 5, 9)
assert -1 == str1.find("r", 5, 7)

str5 = _FakeString("foo{0}baz")
str6 = _FakeString("foo{abc}baz")
str7 = _FakeString("foo{0}{abc}buzz")
str8 = _FakeString("{0}{1}")
self.assertEqual("fake string", str1.format())
self.assertEqual("foobarbaz", str5.format("bar"))
self.assertEqual("foobarbaz", str6.format(abc="bar"))
self.assertEqual("foobarbazbuzz", str7.format("bar", abc="baz"))
self.assertRaises(IndexError, str8.format, "abc")

self.assertEqual("fake string", str1.format_map({}))
self.assertEqual("foobarbaz", str6.format_map({"abc": "bar"}))
self.assertRaises(ValueError, str5.format_map, {0: "abc"})

self.assertEqual(3, str1.index("e"))
self.assertRaises(ValueError, str1.index, "z")
self.assertEqual(7, str1.index("r", 7))
self.assertRaises(ValueError, str1.index, "r", 8)
self.assertEqual(7, str1.index("r", 5, 9))
self.assertRaises(ValueError, str1.index, "r", 5, 7)

assert "fake string" == str1.format()
assert "foobarbaz" == str5.format("bar")
assert "foobarbaz" == str6.format(abc="bar")
assert "foobarbazbuzz" == str7.format("bar", abc="baz")
with pytest.raises(IndexError):
str8.format("abc")

assert "fake string" == str1.format_map({})
assert "foobarbaz" == str6.format_map({"abc": "bar"})
with pytest.raises(ValueError):
str5.format_map({0: "abc"})

assert 3 == str1.index("e")
with pytest.raises(ValueError):
str1.index("z")
assert 7 == str1.index("r", 7)
with pytest.raises(ValueError):
str1.index("r", 8)
assert 7 == str1.index("r", 5, 9)
with pytest.raises(ValueError):
str1.index("r", 5, 7)
str9 = _FakeString("foobar")
str10 = _FakeString("foobar123")
str11 = _FakeString("foo bar")
self.assertTrue(str9.isalnum())
self.assertTrue(str10.isalnum())
self.assertFalse(str11.isalnum())
assert str9.isalnum() is True
assert str10.isalnum() is True
assert str11.isalnum() is False

self.assertTrue(str9.isalpha())
self.assertFalse(str10.isalpha())
self.assertFalse(str11.isalpha())
assert str9.isalpha() is True
assert str10.isalpha() is False
assert str11.isalpha() is False

str12 = _FakeString("123")
str13 = _FakeString("\u2155")
str14 = _FakeString("\u00B2")
self.assertFalse(str9.isdecimal())
self.assertTrue(str12.isdecimal())
self.assertFalse(str13.isdecimal())
self.assertFalse(str14.isdecimal())
assert str9.isdecimal() is False
assert str12.isdecimal() is True
assert str13.isdecimal() is False
assert str14.isdecimal() is False

self.assertFalse(str9.isdigit())
self.assertTrue(str12.isdigit())
self.assertFalse(str13.isdigit())
self.assertTrue(str14.isdigit())
assert str9.isdigit() is False
assert str12.isdigit() is True
assert str13.isdigit() is False
assert str14.isdigit() is True

self.assertTrue(str9.isidentifier())
self.assertTrue(str10.isidentifier())
self.assertFalse(str11.isidentifier())
self.assertFalse(str12.isidentifier())
assert str9.isidentifier() is True
assert str10.isidentifier() is True
assert str11.isidentifier() is False
assert str12.isidentifier() is False

str15 = _FakeString("")
str16 = _FakeString("FooBar")
self.assertTrue(str9.islower())
self.assertFalse(str15.islower())
self.assertFalse(str16.islower())
assert str9.islower() is True
assert str15.islower() is False
assert str16.islower() is False

self.assertFalse(str9.isnumeric())
self.assertTrue(str12.isnumeric())
self.assertTrue(str13.isnumeric())
self.assertTrue(str14.isnumeric())
assert str9.isnumeric() is False
assert str12.isnumeric() is True
assert str13.isnumeric() is True
assert str14.isnumeric() is True

str16B = _FakeString("\x01\x02")
self.assertTrue(str9.isprintable())
self.assertTrue(str13.isprintable())
self.assertTrue(str14.isprintable())
self.assertTrue(str15.isprintable())
self.assertFalse(str16B.isprintable())
assert str9.isprintable() is True
assert str13.isprintable() is True
assert str14.isprintable() is True
assert str15.isprintable() is True
assert str16B.isprintable() is False

str17 = _FakeString(" ")
str18 = _FakeString("\t \t \r\n")
self.assertFalse(str1.isspace())
self.assertFalse(str9.isspace())
self.assertTrue(str17.isspace())
self.assertTrue(str18.isspace())
assert str1.isspace() is False
assert str9.isspace() is False
assert str17.isspace() is True
assert str18.isspace() is True

str19 = _FakeString("This Sentence Looks Like A Title")
str20 = _FakeString("This sentence doesn't LookLikeATitle")
self.assertFalse(str15.istitle())
self.assertTrue(str19.istitle())
self.assertFalse(str20.istitle())
assert str15.istitle() is False
assert str19.istitle() is True
assert str20.istitle() is False

str21 = _FakeString("FOOBAR")
self.assertFalse(str9.isupper())
self.assertFalse(str15.isupper())
self.assertTrue(str21.isupper())
assert str9.isupper() is False
assert str15.isupper() is False
assert str21.isupper() is True

self.assertEqual("foobar", str15.join(["foo", "bar"]))
self.assertEqual("foo123bar123baz", str12.join(("foo", "bar", "baz")))
assert "foobar" == str15.join(["foo", "bar"])
assert "foo123bar123baz" == str12.join(("foo", "bar", "baz"))

self.assertEqual("fake string ", str1.ljust(15))
self.assertEqual("fake string ", str1.ljust(16))
self.assertEqual("fake stringqqqq", str1.ljust(15, "q"))
assert "fake string " == str1.ljust(15)
assert "fake string " == str1.ljust(16)
assert "fake stringqqqq" == str1.ljust(15, "q")

str22 = _FakeString("ß")
self.assertEqual("", str15.lower())
self.assertEqual("foobar", str16.lower())
self.assertEqual("ß", str22.lower())
self.assertEqual("", str15.casefold())
self.assertEqual("foobar", str16.casefold())
self.assertEqual("ss", str22.casefold())
assert "" == str15.lower()
assert "foobar" == str16.lower()
assert "ß" == str22.lower()
assert "" == str15.casefold()
assert "foobar" == str16.casefold()
assert "ss" == str22.casefold()

str23 = _FakeString(" fake string ")
self.assertEqual("fake string", str1.lstrip())
self.assertEqual("fake string ", str23.lstrip())
self.assertEqual("ke string", str1.lstrip("abcdef"))
assert "fake string" == str1.lstrip()
assert "fake string " == str23.lstrip()
assert "ke string" == str1.lstrip("abcdef")

self.assertEqual(("fa", "ke", " string"), str1.partition("ke"))
self.assertEqual(("fake string", "", ""), str1.partition("asdf"))
assert ("fa", "ke", " string") == str1.partition("ke")
assert ("fake string", "", "") == str1.partition("asdf")

str24 = _FakeString("boo foo moo")
self.assertEqual("real string", str1.replace("fake", "real"))
self.assertEqual("bu fu moo", str24.replace("oo", "u", 2))

self.assertEqual(3, str1.rfind("e"))
self.assertEqual(-1, str1.rfind("z"))
self.assertEqual(7, str1.rfind("r", 7))
self.assertEqual(-1, str1.rfind("r", 8))
self.assertEqual(7, str1.rfind("r", 5, 9))
self.assertEqual(-1, str1.rfind("r", 5, 7))

self.assertEqual(3, str1.rindex("e"))
self.assertRaises(ValueError, str1.rindex, "z")
self.assertEqual(7, str1.rindex("r", 7))
self.assertRaises(ValueError, str1.rindex, "r", 8)
self.assertEqual(7, str1.rindex("r", 5, 9))
self.assertRaises(ValueError, str1.rindex, "r", 5, 7)

self.assertEqual(" fake string", str1.rjust(15))
self.assertEqual(" fake string", str1.rjust(16))
self.assertEqual("qqqqfake string", str1.rjust(15, "q"))

self.assertEqual(("fa", "ke", " string"), str1.rpartition("ke"))
self.assertEqual(("", "", "fake string"), str1.rpartition("asdf"))
assert "real string" == str1.replace("fake", "real")
assert "bu fu moo" == str24.replace("oo", "u", 2)

assert 3 == str1.rfind("e")
assert -1 == str1.rfind("z")
assert 7 == str1.rfind("r", 7)
assert -1 == str1.rfind("r", 8)
assert 7 == str1.rfind("r", 5, 9)
assert -1 == str1.rfind("r", 5, 7)

assert 3 == str1.rindex("e")
with pytest.raises(ValueError):
str1.rindex("z")
assert 7 == str1.rindex("r", 7)
with pytest.raises(ValueError):
str1.rindex("r", 8)
assert 7 == str1.rindex("r", 5, 9)
with pytest.raises(ValueError):
str1.rindex("r", 5, 7)
assert " fake string" == str1.rjust(15)
assert " fake string" == str1.rjust(16)
assert "qqqqfake string" == str1.rjust(15, "q")

assert ("fa", "ke", " string") == str1.rpartition("ke")
assert ("", "", "fake string") == str1.rpartition("asdf")

str25 = _FakeString(" this is a sentence with whitespace ")
actual = ["this", "is", "a", "sentence", "with", "whitespace"]
self.assertEqual(actual, str25.rsplit())
self.assertEqual(actual, str25.rsplit(None))
assert actual == str25.rsplit()
assert actual == str25.rsplit(None)
actual = ["", "", "", "this", "is", "a", "", "", "sentence", "with",
"", "whitespace", ""]
self.assertEqual(actual, str25.rsplit(" "))
assert actual == str25.rsplit(" ")
actual = [" this is a", "sentence", "with", "whitespace"]
self.assertEqual(actual, str25.rsplit(None, 3))
assert actual == str25.rsplit(None, 3)
actual = [" this is a sentence with", "", "whitespace", ""]
self.assertEqual(actual, str25.rsplit(" ", 3))
assert actual == str25.rsplit(" ", 3)
actual = [" this is a", "sentence", "with", "whitespace"]
self.assertEqual(actual, str25.rsplit(maxsplit=3))
assert actual == str25.rsplit(maxsplit=3)

self.assertEqual("fake string", str1.rstrip())
self.assertEqual(" fake string", str23.rstrip())
self.assertEqual("fake stri", str1.rstrip("ngr"))
assert "fake string" == str1.rstrip()
assert " fake string" == str23.rstrip()
assert "fake stri" == str1.rstrip("ngr")

actual = ["this", "is", "a", "sentence", "with", "whitespace"]
self.assertEqual(actual, str25.split())
self.assertEqual(actual, str25.split(None))
assert actual == str25.split()
assert actual == str25.split(None)
actual = ["", "", "", "this", "is", "a", "", "", "sentence", "with",
"", "whitespace", ""]
self.assertEqual(actual, str25.split(" "))
assert actual == str25.split(" ")
actual = ["this", "is", "a", "sentence with whitespace "]
self.assertEqual(actual, str25.split(None, 3))
assert actual == str25.split(None, 3)
actual = ["", "", "", "this is a sentence with whitespace "]
self.assertEqual(actual, str25.split(" ", 3))
assert actual == str25.split(" ", 3)
actual = ["this", "is", "a", "sentence with whitespace "]
self.assertEqual(actual, str25.split(maxsplit=3))
assert actual == str25.split(maxsplit=3)

str26 = _FakeString("lines\nof\ntext\r\nare\r\npresented\nhere")
self.assertEqual(["lines", "of", "text", "are", "presented", "here"],
str26.splitlines())
self.assertEqual(["lines\n", "of\n", "text\r\n", "are\r\n",
"presented\n", "here"], str26.splitlines(True))
assert ["lines", "of", "text", "are", "presented", "here"] \
== str26.splitlines()
assert ["lines\n", "of\n", "text\r\n", "are\r\n", "presented\n", "here"] \
== str26.splitlines(True)

self.assertTrue(str1.startswith("fake"))
self.assertFalse(str1.startswith("faker"))
assert str1.startswith("fake") is True
assert str1.startswith("faker") is False

self.assertEqual("fake string", str1.strip())
self.assertEqual("fake string", str23.strip())
self.assertEqual("ke stri", str1.strip("abcdefngr"))
assert "fake string" == str1.strip()
assert "fake string" == str23.strip()
assert "ke stri" == str1.strip("abcdefngr")

self.assertEqual("fOObAR", str16.swapcase())
assert "fOObAR" == str16.swapcase()

self.assertEqual("Fake String", str1.title())
assert "Fake String" == str1.title()

table1 = StringMixIn.maketrans({97: "1", 101: "2", 105: "3",
111: "4", 117: "5"})
table2 = StringMixIn.maketrans("aeiou", "12345")
table3 = StringMixIn.maketrans("aeiou", "12345", "rts")
self.assertEqual("f1k2 str3ng", str1.translate(table1))
self.assertEqual("f1k2 str3ng", str1.translate(table2))
self.assertEqual("f1k2 3ng", str1.translate(table3))

self.assertEqual("", str15.upper())
self.assertEqual("FOOBAR", str16.upper())
assert "f1k2 str3ng" == str1.translate(table1)
assert "f1k2 str3ng" == str1.translate(table2)
assert "f1k2 3ng" == str1.translate(table3)

self.assertEqual("123", str12.zfill(3))
self.assertEqual("000123", str12.zfill(6))
assert "" == str15.upper()
assert "FOOBAR" == str16.upper()

if __name__ == "__main__":
unittest.main(verbosity=2)
assert "123" == str12.zfill(3)
assert "000123" == str12.zfill(6)

+ 133
- 124
tests/test_tag.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Tag, Template, Text
from mwparserfromhell.nodes.extras import Attribute
@@ -52,15 +52,15 @@ class TestTag(TreeEqualityTestCase):
node8 = Tag(wraptext("hr"), wiki_markup="----", self_closing=True)
node9 = Tag(wraptext("i"), wraptext("italics!"), wiki_markup="''")

self.assertEqual("<ref></ref>", str(node1))
self.assertEqual('<span style="color: red;">foo</span>', str(node2))
self.assertEqual("<ref name=foo some_attr/>", str(node3))
self.assertEqual("<br />", str(node4))
self.assertEqual("<br>", str(node5))
self.assertEqual("</br>", str(node6))
self.assertEqual("</br />", str(node7))
self.assertEqual("----", str(node8))
self.assertEqual("''italics!''", str(node9))
assert "<ref></ref>" == str(node1)
assert '<span style="color: red;">foo</span>' == str(node2)
assert "<ref name=foo some_attr/>" == str(node3)
assert "<br />" == str(node4)
assert "<br>" == str(node5)
assert "</br>" == str(node6)
assert "</br />" == str(node7)
assert "----" == str(node8)
assert "''italics!''" == str(node9)

def test_children(self):
"""test Tag.__children__()"""
@@ -77,19 +77,22 @@ class TestTag(TreeEqualityTestCase):
gen1 = node1.__children__()
gen2 = node2.__children__()
gen3 = node3.__children__()
self.assertEqual(node1.tag, next(gen1))
self.assertEqual(node3.tag, next(gen3))
self.assertEqual(node3.attributes[0].name, next(gen3))
self.assertEqual(node3.attributes[0].value, next(gen3))
self.assertEqual(node3.attributes[1].name, next(gen3))
self.assertEqual(node3.attributes[1].value, next(gen3))
self.assertEqual(node3.attributes[2].name, next(gen3))
self.assertEqual(node1.contents, next(gen1))
self.assertEqual(node2.contents, next(gen2))
self.assertEqual(node1.closing_tag, next(gen1))
self.assertRaises(StopIteration, next, gen1)
self.assertRaises(StopIteration, next, gen2)
self.assertRaises(StopIteration, next, gen3)
assert node1.tag == next(gen1)
assert node3.tag == next(gen3)
assert node3.attributes[0].name == next(gen3)
assert node3.attributes[0].value == next(gen3)
assert node3.attributes[1].name == next(gen3)
assert node3.attributes[1].value == next(gen3)
assert node3.attributes[2].name == next(gen3)
assert node1.contents == next(gen1)
assert node2.contents == next(gen2)
assert node1.closing_tag == next(gen1)
with pytest.raises(StopIteration):
next(gen1)
with pytest.raises(StopIteration):
next(gen2)
with pytest.raises(StopIteration):
next(gen3)

def test_strip(self):
"""test Tag.__strip__()"""
@@ -97,9 +100,9 @@ class TestTag(TreeEqualityTestCase):
node2 = Tag(wraptext("math"), wraptext("foobar"))
node3 = Tag(wraptext("br"), self_closing=True)

self.assertEqual("foobar", node1.__strip__())
self.assertEqual(None, node2.__strip__())
self.assertEqual(None, node3.__strip__())
assert "foobar" == node1.__strip__()
assert None == node2.__strip__()
assert None == node3.__strip__()

def test_showtree(self):
"""test Tag.__showtree__()"""
@@ -121,180 +124,186 @@ class TestTag(TreeEqualityTestCase):
(getter, node1.attributes[1].name), ">", (getter, node1.contents),
"</", (getter, node1.closing_tag), ">", "<", (getter, node2.tag),
"/>", "</", (getter, node3.tag), ">"]
self.assertEqual(valid, output)
assert valid == output

def test_tag(self):
"""test getter/setter for the tag attribute"""
tag = wraptext("ref")
node = Tag(tag, wraptext("text"))
self.assertIs(tag, node.tag)
self.assertIs(tag, node.closing_tag)
assert tag is node.tag
assert tag is node.closing_tag
node.tag = "span"
self.assertWikicodeEqual(wraptext("span"), node.tag)
self.assertWikicodeEqual(wraptext("span"), node.closing_tag)
self.assertEqual("<span>text</span>", node)
assert "<span>text</span>" == node

def test_contents(self):
"""test getter/setter for the contents attribute"""
contents = wraptext("text")
node = Tag(wraptext("ref"), contents)
self.assertIs(contents, node.contents)
assert contents is node.contents
node.contents = "text and a {{template}}"
parsed = wrap([Text("text and a "), Template(wraptext("template"))])
self.assertWikicodeEqual(parsed, node.contents)
self.assertEqual("<ref>text and a {{template}}</ref>", node)
assert "<ref>text and a {{template}}</ref>" == node

def test_attributes(self):
"""test getter for the attributes attribute"""
attrs = [agen("name", "bar")]
node1 = Tag(wraptext("ref"), wraptext("foo"))
node2 = Tag(wraptext("ref"), wraptext("foo"), attrs)
self.assertEqual([], node1.attributes)
self.assertIs(attrs, node2.attributes)
assert [] == node1.attributes
assert attrs is node2.attributes

def test_wiki_markup(self):
"""test getter/setter for the wiki_markup attribute"""
node = Tag(wraptext("i"), wraptext("italic text"))
self.assertIs(None, node.wiki_markup)
assert None is node.wiki_markup
node.wiki_markup = "''"
self.assertEqual("''", node.wiki_markup)
self.assertEqual("''italic text''", node)
assert "''" == node.wiki_markup
assert "''italic text''" == node
node.wiki_markup = False
self.assertFalse(node.wiki_markup)
self.assertEqual("<i>italic text</i>", node)
assert node.wiki_markup is None
assert "<i>italic text</i>" == node

def test_self_closing(self):
"""test getter/setter for the self_closing attribute"""
node = Tag(wraptext("ref"), wraptext("foobar"))
self.assertFalse(node.self_closing)
assert node.self_closing is False
node.self_closing = True
self.assertTrue(node.self_closing)
self.assertEqual("<ref/>", node)
assert node.self_closing is True
assert "<ref/>" == node
node.self_closing = 0
self.assertFalse(node.self_closing)
self.assertEqual("<ref>foobar</ref>", node)
assert node.self_closing is False
assert "<ref>foobar</ref>" == node

def test_invalid(self):
"""test getter/setter for the invalid attribute"""
node = Tag(wraptext("br"), self_closing=True, implicit=True)
self.assertFalse(node.invalid)
assert node.invalid is False
node.invalid = True
self.assertTrue(node.invalid)
self.assertEqual("</br>", node)
assert node.invalid is True
assert "</br>" == node
node.invalid = 0
self.assertFalse(node.invalid)
self.assertEqual("<br>", node)
assert node.invalid is False
assert "<br>" == node

def test_implicit(self):
"""test getter/setter for the implicit attribute"""
node = Tag(wraptext("br"), self_closing=True)
self.assertFalse(node.implicit)
assert node.implicit is False
node.implicit = True
self.assertTrue(node.implicit)
self.assertEqual("<br>", node)
assert node.implicit is True
assert "<br>" == node
node.implicit = 0
self.assertFalse(node.implicit)
self.assertEqual("<br/>", node)
assert node.implicit is False
assert "<br/>" == node

def test_padding(self):
"""test getter/setter for the padding attribute"""
node = Tag(wraptext("ref"), wraptext("foobar"))
self.assertEqual("", node.padding)
assert "" == node.padding
node.padding = " "
self.assertEqual(" ", node.padding)
self.assertEqual("<ref >foobar</ref>", node)
assert " " == node.padding
assert "<ref >foobar</ref>" == node
node.padding = None
self.assertEqual("", node.padding)
self.assertEqual("<ref>foobar</ref>", node)
self.assertRaises(ValueError, setattr, node, "padding", True)
assert "" == node.padding
assert "<ref>foobar</ref>" == node
with pytest.raises(ValueError):
node.__setattr__("padding", True)

def test_closing_tag(self):
"""test getter/setter for the closing_tag attribute"""
tag = wraptext("ref")
node = Tag(tag, wraptext("foobar"))
self.assertIs(tag, node.closing_tag)
assert tag is node.closing_tag
node.closing_tag = "ref {{ignore me}}"
parsed = wrap([Text("ref "), Template(wraptext("ignore me"))])
self.assertWikicodeEqual(parsed, node.closing_tag)
self.assertEqual("<ref>foobar</ref {{ignore me}}>", node)
assert "<ref>foobar</ref {{ignore me}}>" == node

def test_wiki_style_separator(self):
"""test getter/setter for wiki_style_separator attribute"""
node = Tag(wraptext("table"), wraptext("\n"))
self.assertIs(None, node.wiki_style_separator)
assert None is node.wiki_style_separator
node.wiki_style_separator = "|"
self.assertEqual("|", node.wiki_style_separator)
assert "|" == node.wiki_style_separator
node.wiki_markup = "{"
self.assertEqual("{|\n{", node)
assert "{|\n{" == node
node2 = Tag(wraptext("table"), wraptext("\n"), wiki_style_separator="|")
self.assertEqual("|", node.wiki_style_separator)
assert "|" == node.wiki_style_separator

def test_closing_wiki_markup(self):
"""test getter/setter for closing_wiki_markup attribute"""
node = Tag(wraptext("table"), wraptext("\n"))
self.assertIs(None, node.closing_wiki_markup)
assert None is node.closing_wiki_markup
node.wiki_markup = "{|"
self.assertEqual("{|", node.closing_wiki_markup)
assert "{|" == node.closing_wiki_markup
node.closing_wiki_markup = "|}"
self.assertEqual("|}", node.closing_wiki_markup)
self.assertEqual("{|\n|}", node)
assert "|}" == node.closing_wiki_markup
assert "{|\n|}" == node
node.wiki_markup = "!!"
self.assertEqual("|}", node.closing_wiki_markup)
self.assertEqual("!!\n|}", node)
assert "|}" == node.closing_wiki_markup
assert "!!\n|}" == node
node.wiki_markup = False
self.assertFalse(node.closing_wiki_markup)
self.assertEqual("<table>\n</table>", node)
assert node.closing_wiki_markup is None
assert "<table>\n</table>" == node
node2 = Tag(wraptext("table"), wraptext("\n"),
attrs=[agen("id", "foo")], wiki_markup="{|",
closing_wiki_markup="|}")
self.assertEqual("|}", node2.closing_wiki_markup)
self.assertEqual('{| id="foo"\n|}', node2)
assert "|}" == node2.closing_wiki_markup
assert '{| id="foo"\n|}' == node2

def test_has(self):
"""test Tag.has()"""
node = Tag(wraptext("ref"), wraptext("cite"), [agen("name", "foo")])
self.assertTrue(node.has("name"))
self.assertTrue(node.has(" name "))
self.assertTrue(node.has(wraptext("name")))
self.assertFalse(node.has("Name"))
self.assertFalse(node.has("foo"))
assert node.has("name") is True
assert node.has(" name ") is True
assert node.has(wraptext("name")) is True
assert node.has("Name") is False
assert node.has("foo") is False

attrs = [agen("id", "foo"), agenp("class", "bar", " ", "\n", "\n"),
agen("foo", "bar"), agenpnv("foo", " ", " \n ", " \t")]
node2 = Tag(wraptext("div"), attrs=attrs, self_closing=True)
self.assertTrue(node2.has("id"))
self.assertTrue(node2.has("class"))
self.assertTrue(node2.has(attrs[1].pad_first + str(attrs[1].name) +
attrs[1].pad_before_eq))
self.assertTrue(node2.has(attrs[3]))
self.assertTrue(node2.has(str(attrs[3])))
self.assertFalse(node2.has("idclass"))
self.assertFalse(node2.has("id class"))
self.assertFalse(node2.has("id=foo"))
assert node2.has("id") is True
assert node2.has("class") is True
assert node2.has(attrs[1].pad_first + str(attrs[1].name) +
attrs[1].pad_before_eq) is True
assert node2.has(attrs[3]) is True
assert node2.has(str(attrs[3])) is True
assert node2.has("idclass") is False
assert node2.has("id class") is False
assert node2.has("id=foo") is False

def test_get(self):
"""test Tag.get()"""
attrs = [agen("name", "foo")]
node = Tag(wraptext("ref"), wraptext("cite"), attrs)
self.assertIs(attrs[0], node.get("name"))
self.assertIs(attrs[0], node.get(" name "))
self.assertIs(attrs[0], node.get(wraptext("name")))
self.assertRaises(ValueError, node.get, "Name")
self.assertRaises(ValueError, node.get, "foo")
assert attrs[0] is node.get("name")
assert attrs[0] is node.get(" name ")
assert attrs[0] is node.get(wraptext("name"))
with pytest.raises(ValueError):
node.get("Name")
with pytest.raises(ValueError):
node.get("foo")

attrs = [agen("id", "foo"), agenp("class", "bar", " ", "\n", "\n"),
agen("foo", "bar"), agenpnv("foo", " ", " \n ", " \t")]
node2 = Tag(wraptext("div"), attrs=attrs, self_closing=True)
self.assertIs(attrs[0], node2.get("id"))
self.assertIs(attrs[1], node2.get("class"))
self.assertIs(attrs[1], node2.get(
attrs[1].pad_first + str(attrs[1].name) + attrs[1].pad_before_eq))
self.assertIs(attrs[3], node2.get(attrs[3]))
self.assertIs(attrs[3], node2.get(str(attrs[3])))
self.assertIs(attrs[3], node2.get(" foo"))
self.assertRaises(ValueError, node2.get, "idclass")
self.assertRaises(ValueError, node2.get, "id class")
self.assertRaises(ValueError, node2.get, "id=foo")
assert attrs[0] is node2.get("id")
assert attrs[1] is node2.get("class")
assert attrs[1] is node2.get(
attrs[1].pad_first + str(attrs[1].name) + attrs[1].pad_before_eq)
assert attrs[3] is node2.get(attrs[3])
assert attrs[3] is node2.get(str(attrs[3]))
assert attrs[3] is node2.get(" foo")
with pytest.raises(ValueError):
node2.get("idclass")
with pytest.raises(ValueError):
node2.get("id class")
with pytest.raises(ValueError):
node2.get("id=foo")

def test_add(self):
"""test Tag.add()"""
@@ -313,20 +322,22 @@ class TestTag(TreeEqualityTestCase):
attr5 = ' 1="False"'
attr6 = ' style="{{foobar}}"'
attr7 = '\nname = "value"'
self.assertEqual(attr1, node.attributes[0])
self.assertEqual(attr2, node.attributes[1])
self.assertEqual(attr3, node.attributes[2])
self.assertEqual(attr4, node.attributes[3])
self.assertEqual(attr5, node.attributes[4])
self.assertEqual(attr6, node.attributes[5])
self.assertEqual(attr7, node.attributes[6])
self.assertEqual(attr7, node.get("name"))
assert attr1 == node.attributes[0]
assert attr2 == node.attributes[1]
assert attr3 == node.attributes[2]
assert attr4 == node.attributes[3]
assert attr5 == node.attributes[4]
assert attr6 == node.attributes[5]
assert attr7 == node.attributes[6]
assert attr7 == node.get("name")
self.assertWikicodeEqual(wrap([Template(wraptext("foobar"))]),
node.attributes[5].value)
self.assertEqual("".join(("<ref", attr1, attr2, attr3, attr4, attr5,
attr6, attr7, ">cite</ref>")), node)
self.assertRaises(ValueError, node.add, "name", "foo", quotes="bar")
self.assertRaises(ValueError, node.add, "name", "a bc d", quotes=None)
assert "".join(("<ref", attr1, attr2, attr3, attr4, attr5,
attr6, attr7, ">cite</ref>")) == node
with pytest.raises(ValueError):
node.add("name", "foo", quotes="bar")
with pytest.raises(ValueError):
node.add("name", "a bc d", quotes=None)

def test_remove(self):
"""test Tag.remove()"""
@@ -334,12 +345,10 @@ class TestTag(TreeEqualityTestCase):
agen("foo", "bar"), agenpnv("foo", " ", " \n ", " \t")]
node = Tag(wraptext("div"), attrs=attrs, self_closing=True)
node.remove("class")
self.assertEqual('<div id="foo" foo="bar" foo \n />', node)
assert '<div id="foo" foo="bar" foo \n />' == node
node.remove("foo")
self.assertEqual('<div id="foo"/>', node)
self.assertRaises(ValueError, node.remove, "foo")
assert '<div id="foo"/>' == node
with pytest.raises(ValueError):
node.remove("foo")
node.remove("id")
self.assertEqual('<div/>', node)

if __name__ == "__main__":
unittest.main(verbosity=2)
assert '<div/>' == node

+ 129
- 123
tests/test_template.py View File

@@ -20,7 +20,7 @@
# SOFTWARE.

from difflib import unified_diff
import unittest
import pytest

from mwparserfromhell.nodes import HTMLEntity, Template, Text
from mwparserfromhell.nodes.extras import Parameter
@@ -37,10 +37,10 @@ class TestTemplate(TreeEqualityTestCase):
def test_unicode(self):
"""test Template.__unicode__()"""
node = Template(wraptext("foobar"))
self.assertEqual("{{foobar}}", str(node))
assert "{{foobar}}" == str(node)
node2 = Template(wraptext("foo"),
[pgenh("1", "bar"), pgens("abc", "def")])
self.assertEqual("{{foo|bar|abc=def}}", str(node2))
assert "{{foo|bar|abc=def}}" == str(node2)

def test_children(self):
"""test Template.__children__()"""
@@ -52,13 +52,15 @@ class TestTemplate(TreeEqualityTestCase):

gen1 = node1.__children__()
gen2 = node2.__children__()
self.assertEqual(node1.name, next(gen1))
self.assertEqual(node2.name, next(gen2))
self.assertEqual(node2.params[0].value, next(gen2))
self.assertEqual(node2.params[1].name, next(gen2))
self.assertEqual(node2.params[1].value, next(gen2))
self.assertRaises(StopIteration, next, gen1)
self.assertRaises(StopIteration, next, gen2)
assert node1.name == next(gen1)
assert node2.name == next(gen2)
assert node2.params[0].value == next(gen2)
assert node2.params[1].name == next(gen2)
assert node2.params[1].value == next(gen2)
with pytest.raises(StopIteration):
next(gen1)
with pytest.raises(StopIteration):
next(gen2)

def test_strip(self):
"""test Template.__strip__()"""
@@ -71,11 +73,11 @@ class TestTemplate(TreeEqualityTestCase):
showkey=False),
pgenh("3", "bar")])

self.assertEqual(None, node1.__strip__(keep_template_params=False))
self.assertEqual(None, node2.__strip__(keep_template_params=False))
self.assertEqual("", node1.__strip__(keep_template_params=True))
self.assertEqual("bar def", node2.__strip__(keep_template_params=True))
self.assertEqual("foo bar", node3.__strip__(keep_template_params=True))
assert node1.__strip__(keep_template_params=False) is None
assert node2.__strip__(keep_template_params=False) is None
assert "" == node1.__strip__(keep_template_params=True)
assert "bar def" == node2.__strip__(keep_template_params=True)
assert "foo bar" == node3.__strip__(keep_template_params=True)

def test_showtree(self):
"""test Template.__showtree__()"""
@@ -94,15 +96,15 @@ class TestTemplate(TreeEqualityTestCase):
(getter, node2.params[0].value), " | ", marker,
(getter, node2.params[1].name), " = ", marker,
(getter, node2.params[1].value), "}}"]
self.assertEqual(valid, output)
assert 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)
assert name is node1.name
assert name is node2.name
node1.name = "asdf"
node2.name = "téstïng"
self.assertWikicodeEqual(wraptext("asdf"), node1.name)
@@ -113,8 +115,8 @@ class TestTemplate(TreeEqualityTestCase):
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)
assert [] == node1.params
assert plist is node2.params

def test_has(self):
"""test Template.has()"""
@@ -124,17 +126,17 @@ class TestTemplate(TreeEqualityTestCase):
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("foobar", False))
self.assertTrue(node2.has(1, False))
self.assertTrue(node2.has("abc", False))
self.assertFalse(node2.has("def", False))
self.assertTrue(node3.has("1", False))
self.assertTrue(node3.has(" b ", False))
self.assertTrue(node4.has("b", False))
self.assertTrue(node3.has("b", True))
self.assertFalse(node4.has("b", True))
self.assertFalse(node1.has_param("foobar", False))
self.assertTrue(node2.has_param(1, False))
assert node1.has("foobar", False) is False
assert node2.has(1, False) is True
assert node2.has("abc", False) is True
assert node2.has("def", False) is False
assert node3.has("1", False) is True
assert node3.has(" b ", False) is True
assert node4.has("b", False) is True
assert node3.has("b", True) is True
assert node4.has("b", True) is False
assert node1.has_param("foobar", False) is False
assert node2.has_param(1, False) is True

def test_get(self):
"""test Template.get()"""
@@ -147,13 +149,15 @@ class TestTemplate(TreeEqualityTestCase):
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 "))
with pytest.raises(ValueError):
node1.get("foobar")
assert node2p1 is node2.get(1)
assert node2p2 is node2.get("abc")
with pytest.raises(ValueError):
node2.get("def")
assert node3p1 is node3.get("b")
assert node3p2 is node3.get("1")
assert node4p1 is node4.get("b ")

def test_add(self):
"""test Template.add()"""
@@ -227,12 +231,12 @@ class TestTemplate(TreeEqualityTestCase):
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")
with pytest.raises(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"))
with pytest.raises(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)
@@ -261,59 +265,60 @@ class TestTemplate(TreeEqualityTestCase):
node36.add("d", "h", before="b")
node37.add(1, "b")
node38.add("1", "foo")
self.assertRaises(ValueError, node38.add, "z", "bar", showkey=False)
with pytest.raises(ValueError):
node38.add("z", "bar", showkey=False)
node39.add("1", "c")
node40.add("3", "d")
node41.add("3", "d")
node42.add("b", "hello")

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&#124;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&#61;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 |\nh = i}}", node15)
self.assertEqual("{{a|\nb = c|\nd = e|\nf = g|h=i}}", node16)
self.assertEqual("{{a|b|c}}", node17)
self.assertEqual("{{a|b|3=c}}", node18)
self.assertEqual("{{a|b|c=d}}", node19)
self.assertEqual("{{a|b|c|d|e|f}}", node20)
self.assertEqual("{{a|b|c|4=d|5=e|f}}", node21)
self.assertEqual("{{a|b|c|4=d|5=e|6=f}}", node22)
self.assertEqual("{{a|b|c=foo=bar}}", node23)
self.assertEqual("{{a|b|foo&#61;bar}}", node24)
self.assertIsInstance(node24.params[1].value.get(1), HTMLEntity)
self.assertEqual("{{a|b=d}}", node25)
self.assertEqual("{{a|foo&#61;bar}}", node26)
self.assertIsInstance(node26.params[0].value.get(1), HTMLEntity)
self.assertEqual("{{a|1=foo=bar}}", node27)
self.assertEqual("{{a|foo&#61;bar}}", node28)
self.assertIsInstance(node28.params[0].value.get(1), HTMLEntity)
self.assertEqual("{{a|\nb = c|\nd = foo|\nf = g}}", node29)
self.assertEqual("{{a\n|b =c\n|d = e|f =foo\n|h = i\n}}", node30)
self.assertEqual("{{a|b = c\n|\nd = e|\nf =foo }}", node31)
self.assertEqual("{{a|\nb = c |\nd =foo|\nf = g }}", node32)
self.assertEqual("{{a|b=k|d=e|i=j}}", node33)
self.assertEqual("{{a|1=e|x=y|2=d}}", node34)
self.assertEqual("{{a|x=y|e|d}}", node35)
self.assertEqual("{{a|b=c|d=h|f=g}}", node36)
self.assertEqual("{{a|b}}", node37)
self.assertEqual("{{abc|foo}}", node38)
self.assertEqual("{{a|c}}", node39)
self.assertEqual("{{a| b| c|d}}", node40)
self.assertEqual("{{a|1= b|2= c|3= d}}", node41)
self.assertEqual("{{a|b=hello \n}}", node42)
assert "{{a|b=c|d|e=f}}" == node1
assert "{{a|b=c|d|g}}" == node2
assert "{{a|b=c|d|e=foo&#124;bar}}" == node3
assert isinstance(node3.params[2].value.get(1), HTMLEntity)
assert "{{a|e=f|b=c|d}}" == node4
assert "{{a|b=c|f=g| d =e}}" == node5
assert "{{a|b=c|b=d|f=g|b=e}}" == node6
assert "{{a|b=c|d}}" == node7
assert "{{a|b=c|e=f|d}}" == node8
assert "{{a|b=c|e=f|d}}" == node9
assert "{{a|b=c|e}}" == node10
assert "{{a|b=c|d=foo=bar}}" == node11
assert "{{a|b=c|foo&#61;bar}}" == node12
assert isinstance(node12.params[1].value.get(1), HTMLEntity)
assert "{{a|\nb = c|\nd = e|\nf = g|\nh = i}}" == node13
assert "{{a\n|b =c\n|d = e|f =g\n|h = i\n|j =k\n}}" == node14
assert "{{a|b = c\n|\nd = e|\nf =g |\nh = i}}" == node15
assert "{{a|\nb = c|\nd = e|\nf = g|h=i}}" == node16
assert "{{a|b|c}}" == node17
assert "{{a|b|3=c}}" == node18
assert "{{a|b|c=d}}" == node19
assert "{{a|b|c|d|e|f}}" == node20
assert "{{a|b|c|4=d|5=e|f}}" == node21
assert "{{a|b|c|4=d|5=e|6=f}}" == node22
assert "{{a|b|c=foo=bar}}" == node23
assert "{{a|b|foo&#61;bar}}" == node24
assert isinstance(node24.params[1].value.get(1), HTMLEntity)
assert "{{a|b=d}}" == node25
assert "{{a|foo&#61;bar}}" == node26
assert isinstance(node26.params[0].value.get(1), HTMLEntity)
assert "{{a|1=foo=bar}}" == node27
assert "{{a|foo&#61;bar}}" == node28
assert isinstance(node28.params[0].value.get(1), HTMLEntity)
assert "{{a|\nb = c|\nd = foo|\nf = g}}" == node29
assert "{{a\n|b =c\n|d = e|f =foo\n|h = i\n}}" == node30
assert "{{a|b = c\n|\nd = e|\nf =foo }}" == node31
assert "{{a|\nb = c |\nd =foo|\nf = g }}" == node32
assert "{{a|b=k|d=e|i=j}}" == node33
assert "{{a|1=e|x=y|2=d}}" == node34
assert "{{a|x=y|e|d}}" == node35
assert "{{a|b=c|d=h|f=g}}" == node36
assert "{{a|b}}" == node37
assert "{{abc|foo}}" == node38
assert "{{a|c}}" == node39
assert "{{a| b| c|d}}" == node40
assert "{{a|1= b|2= c|3= d}}" == node41
assert "{{a|b=hello \n}}" == node42

def test_remove(self):
"""test Template.remove()"""
@@ -405,35 +410,39 @@ class TestTemplate(TreeEqualityTestCase):
node25.remove(node25.params[3], keep_field=False)
node26.remove(node26.params[3], keep_field=True)

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|2=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|2=c}}", node10)
self.assertEqual("{{foo|b=c|a =d}}", node11)
self.assertEqual("{{foo| a=|b=c|a =d}}", node12)
self.assertEqual("{{foo| a=b|a =d}}", node13)
self.assertEqual("{{foo| a=b|b=|a =d}}", node14)
self.assertEqual("{{foo| a=b|b=c}}", node15)
self.assertEqual("{{foo| a=b|b=c|a =}}", node16)
self.assertEqual("{{foo|b|c}}", node17)
self.assertEqual("{{foo|1 =|b|c}}", node18)
self.assertEqual("{{foo|1 =a|2=c}}", node19)
self.assertEqual("{{foo|1 =a||c}}", node20)
self.assertEqual("{{foo|c=d|e=f}}", node21)
self.assertEqual("{{foo|a=|c=d|e=f}}", node22)
self.assertEqual("{{foo|c=d|e=f|a=b|a=b}}", node23)
self.assertEqual("{{foo|a=|c=d|e=f|a=b|a=b}}", node24)
self.assertEqual("{{foo|a=b|c=d|e=f|a=b}}", node25)
self.assertEqual("{{foo|a=b|c=d|e=f|a=|a=b}}", node26)
self.assertRaises(ValueError, node27.remove, node28.get(1))
with pytest.raises(ValueError):
node1.remove(1)
with pytest.raises(ValueError):
node1.remove("a")
with pytest.raises(ValueError):
node2.remove("1")
assert "{{foo}}" == node2
assert "{{foo||abc=}}" == node3
assert "{{foo|2=baz}}" == node4
assert "{{foo|b=c}}" == node5
assert "{{foo| a=|b=c}}" == node6
assert "{{foo|1 =|2=c}}" == node7
assert "{{foo|2=c}}" == node8
assert "{{foo||c}}" == node9
assert "{{foo|2=c}}" == node10
assert "{{foo|b=c|a =d}}" == node11
assert "{{foo| a=|b=c|a =d}}" == node12
assert "{{foo| a=b|a =d}}" == node13
assert "{{foo| a=b|b=|a =d}}" == node14
assert "{{foo| a=b|b=c}}" == node15
assert "{{foo| a=b|b=c|a =}}" == node16
assert "{{foo|b|c}}" == node17
assert "{{foo|1 =|b|c}}" == node18
assert "{{foo|1 =a|2=c}}" == node19
assert "{{foo|1 =a||c}}" == node20
assert "{{foo|c=d|e=f}}" == node21
assert "{{foo|a=|c=d|e=f}}" == node22
assert "{{foo|c=d|e=f|a=b|a=b}}" == node23
assert "{{foo|a=|c=d|e=f|a=b|a=b}}" == node24
assert "{{foo|a=b|c=d|e=f|a=b}}" == node25
assert "{{foo|a=b|c=d|e=f|a=|a=b}}" == node26
with pytest.raises(ValueError):
node27.remove(node28.get(1))

def test_formatting(self):
"""test realistic param manipulation with complex whitespace formatting
@@ -600,7 +609,4 @@ class TestTemplate(TreeEqualityTestCase):
newlines = str(code).splitlines(True)
difflines = unified_diff(oldlines, newlines, n=1)
diff = "".join(list(difflines)[2:]).strip()
self.assertEqual(expected, diff)

if __name__ == "__main__":
unittest.main(verbosity=2)
assert expected == diff

+ 12
- 14
tests/test_text.py View File

@@ -19,30 +19,31 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Text

class TestText(unittest.TestCase):
class TestText:
"""Test cases for the Text node."""

def test_unicode(self):
"""test Text.__unicode__()"""
node = Text("foobar")
self.assertEqual("foobar", str(node))
assert "foobar" == str(node)
node2 = Text("fóóbar")
self.assertEqual("fóóbar", str(node2))
assert "fóóbar" == str(node2)

def test_children(self):
"""test Text.__children__()"""
node = Text("foobar")
gen = node.__children__()
self.assertRaises(StopIteration, next, gen)
with pytest.raises(StopIteration):
next(gen)

def test_strip(self):
"""test Text.__strip__()"""
node = Text("foobar")
self.assertIs(node, node.__strip__())
assert node is node.__strip__()

def test_showtree(self):
"""test Text.__showtree__()"""
@@ -54,16 +55,13 @@ class TestText(unittest.TestCase):
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)
assert 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)
assert "foobar" == node.value
assert isinstance(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)
assert "héhéhé" == node.value
assert isinstance(node.value, str)

+ 134
- 0
tests/test_tokenizer.py View File

@@ -0,0 +1,134 @@
#
# Copyright (C) 2012-2016 Ben Kurtovic <ben.kurtovic@gmail.com>
#
# 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.

import codecs
from os import listdir, path
import pytest
import warnings

from mwparserfromhell.parser import contexts, tokens
from mwparserfromhell.parser.builder import Builder
from mwparserfromhell.parser.tokenizer import Tokenizer as PyTokenizer
try:
from mwparserfromhell.parser._tokenizer import CTokenizer
except ImportError:
CTokenizer = None


class _TestParseError(Exception):
"""Raised internally when a test could not be parsed."""
pass


def _parse_test(test, data):
"""Parse an individual *test*, storing its info in *data*."""
for line in test.strip().splitlines():
if line.startswith("name:"):
data["name"] = line[len("name:"):].strip()
elif line.startswith("label:"):
data["label"] = line[len("label:"):].strip()
elif line.startswith("input:"):
raw = line[len("input:"):].strip()
if raw[0] == '"' and raw[-1] == '"':
raw = raw[1:-1]
raw = raw.encode("raw_unicode_escape")
data["input"] = raw.decode("unicode_escape")
elif line.startswith("output:"):
raw = line[len("output:"):].strip()
try:
data["output"] = eval(raw, vars(tokens))
except Exception as err:
raise _TestParseError(err)


def _load_tests(filename, name, text):
"""Load all tests in *text* from the file *filename*."""
tests = text.split("\n---\n")
for test in tests:
data = {"name": None, "label": None, "input": None, "output": None}
try:
_parse_test(test, data)
except _TestParseError as err:
if data["name"]:
error = "Could not parse test '{0}' in '{1}':\n\t{2}"
warnings.warn(error.format(data["name"], filename, err))
else:
error = "Could not parse a test in '{0}':\n\t{1}"
warnings.warn(error.format(filename, err))
continue

if not data["name"]:
error = "A test in '{0}' was ignored because it lacked a name"
warnings.warn(error.format(filename))
continue
if data["input"] is None or data["output"] is None:
error = "Test '{}' in '{}' was ignored because it lacked an input or an output"
warnings.warn(error.format(data["name"], filename))
continue

# Include test filename in name
data['name'] = '{}:{}'.format(name, data['name'])

yield data


def build():
"""Load and install all tests from the 'tokenizer' directory."""
directory = path.join(path.dirname(__file__), "tokenizer")
extension = ".mwtest"
for filename in listdir(directory):
if not filename.endswith(extension):
continue
fullname = path.join(directory, filename)
with codecs.open(fullname, "r", encoding="utf8") as fp:
text = fp.read()
name = path.split(fullname)[1][:-len(extension)]
yield from _load_tests(fullname, name, text)


@pytest.mark.parametrize("tokenizer", filter(None, (
CTokenizer, PyTokenizer
)), ids=lambda t: 'CTokenizer' if t.USES_C else 'PyTokenizer')
@pytest.mark.parametrize("data", build(), ids=lambda data: data['name'])
def test_tokenizer(tokenizer, data):
expected = data["output"]
actual = tokenizer().tokenize(data["input"])
assert expected == actual


@pytest.mark.parametrize("data", build(), ids=lambda data: data['name'])
def test_roundtrip(data):
expected = data["input"]
actual = str(Builder().build(data["output"][:]))
assert expected == actual


@pytest.mark.skipif(CTokenizer is None, reason='CTokenizer not available')
def test_c_tokenizer_uses_c():
"""make sure the C tokenizer identifies as using a C extension"""
assert CTokenizer.USES_C is True
assert CTokenizer().USES_C is True


def test_describe_context():
assert "" == contexts.describe(0)
ctx = contexts.describe(contexts.TEMPLATE_PARAM_KEY|contexts.HAS_TEXT)
assert "TEMPLATE_PARAM_KEY|HAS_TEXT" == ctx

+ 36
- 39
tests/test_tokens.py View File

@@ -19,39 +19,40 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.parser import tokens

class TestTokens(unittest.TestCase):
class TestTokens:
"""Test cases for the Token class and its subclasses."""

def test_issubclass(self):
@pytest.mark.parametrize("name", tokens.__all__)
def test_issubclass(self, name):
"""check that all classes within the tokens module are really Tokens"""
for name in tokens.__all__:
klass = getattr(tokens, name)
self.assertTrue(issubclass(klass, tokens.Token))
self.assertIsInstance(klass(), klass)
self.assertIsInstance(klass(), tokens.Token)
klass = getattr(tokens, name)
assert issubclass(klass, tokens.Token) is True
assert isinstance(klass(), klass)
assert isinstance(klass(), tokens.Token)

def test_attributes(self):
"""check that Token attributes can be managed properly"""
token1 = tokens.Token()
token2 = tokens.Token(foo="bar", baz=123)

self.assertEqual("bar", token2.foo)
self.assertEqual(123, token2.baz)
self.assertFalse(token1.foo)
self.assertFalse(token2.bar)
assert "bar" == token2.foo
assert 123 == token2.baz
assert token1.foo is None
assert token2.bar is None

token1.spam = "eggs"
token2.foo = "ham"
del token2.baz

self.assertEqual("eggs", token1.spam)
self.assertEqual("ham", token2.foo)
self.assertFalse(token2.baz)
self.assertRaises(KeyError, delattr, token2, "baz")
assert "eggs" == token1.spam
assert "ham" == token2.foo
assert token2.baz is None
with pytest.raises(KeyError):
token2.__delattr__("baz")

def test_repr(self):
"""check that repr() on a Token works as expected"""
@@ -60,13 +61,13 @@ class TestTokens(unittest.TestCase):
token3 = tokens.Text(text="earwig" * 100)
hundredchars = ("earwig" * 100)[:97] + "..."

self.assertEqual("Token()", repr(token1))
assert "Token()" == repr(token1)
token2repr1 = "Token(foo='bar', baz=123)"
token2repr2 = "Token(baz=123, foo='bar')"
token3repr = "Text(text='" + hundredchars + "')"
token2repr = repr(token2)
self.assertTrue(token2repr == token2repr1 or token2repr == token2repr2)
self.assertEqual(token3repr, repr(token3))
assert token2repr == token2repr1 or token2repr == token2repr2
assert token3repr == repr(token3)

def test_equality(self):
"""check that equivalent tokens are considered equal"""
@@ -77,24 +78,20 @@ class TestTokens(unittest.TestCase):
token5 = tokens.Text(text="asdf")
token6 = tokens.TemplateOpen(text="asdf")

self.assertEqual(token1, token2)
self.assertEqual(token2, token1)
self.assertEqual(token4, token5)
self.assertEqual(token5, token4)
self.assertNotEqual(token1, token3)
self.assertNotEqual(token2, token3)
self.assertNotEqual(token4, token6)
self.assertNotEqual(token5, token6)
assert token1 == token2
assert token2 == token1
assert token4 == token5
assert token5 == token4
assert token1 != token3
assert token2 != token3
assert token4 != token6
assert token5 != token6

def test_repr_equality(self):
"check that eval(repr(token)) == token"
tests = [
tokens.Token(),
tokens.Token(foo="bar", baz=123),
tokens.Text(text="earwig")
]
for token in tests:
self.assertEqual(token, eval(repr(token), vars(tokens)))

if __name__ == "__main__":
unittest.main(verbosity=2)
@pytest.mark.parametrize("token", [
tokens.Token(),
tokens.Token(foo="bar", baz=123),
tokens.Text(text="earwig")
])
def test_repr_equality(self, token):
"""check that eval(repr(token)) == token"""
assert token == eval(repr(token), vars(tokens))

+ 24
- 27
tests/test_utils.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Template, Text
from mwparserfromhell.utils import parse_anything
@@ -29,32 +29,29 @@ 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):
@pytest.mark.parametrize("test,valid", [
(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")],
wraptext("foo", "bar", "baz")),
([wraptext("foo"), Text("bar"), "baz", 123, 456],
wraptext("foo", "bar", "baz", "123", "456")),
([[[([[((("foo",),),)], "bar"],)]]], wraptext("foo", "bar"))
])
def test_parse_anything_valid(self, test, valid):
"""tests for valid input to utils.parse_anything()"""
tests = [
(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")],
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))
self.assertWikicodeEqual(valid, parse_anything(test))

def test_parse_anything_invalid(self):
@pytest.mark.parametrize("invalid", [
Ellipsis, object, object(), type,
["foo", [object]]
])
def test_parse_anything_invalid(self, invalid):
"""tests for invalid input to utils.parse_anything()"""
self.assertRaises(ValueError, parse_anything, Ellipsis)
self.assertRaises(ValueError, parse_anything, object)
self.assertRaises(ValueError, parse_anything, object())
self.assertRaises(ValueError, parse_anything, type)
self.assertRaises(ValueError, parse_anything, ["foo", [object]])

if __name__ == "__main__":
unittest.main(verbosity=2)
with pytest.raises(ValueError):
parse_anything(invalid)

+ 236
- 218
tests/test_wikicode.py View File

@@ -20,12 +20,11 @@
# SOFTWARE.

from functools import partial
import pytest
import re
from types import GeneratorType
import unittest

from mwparserfromhell.nodes import (Argument, Comment, Heading, HTMLEntity,
Node, Tag, Template, Text, Wikilink)
from mwparserfromhell.nodes import Argument, Heading, Template, Text
from mwparserfromhell.smart_list import SmartList
from mwparserfromhell.wikicode import Wikicode
from mwparserfromhell import parse
@@ -39,72 +38,79 @@ class TestWikicode(TreeEqualityTestCase):
"""test Wikicode.__unicode__()"""
code1 = parse("foobar")
code2 = parse("Have a {{template}} and a [[page|link]]")
self.assertEqual("foobar", str(code1))
self.assertEqual("Have a {{template}} and a [[page|link]]", str(code2))
assert "foobar" == str(code1)
assert "Have a {{template}} and a [[page|link]]" == str(code2)

def test_nodes(self):
"""test getter/setter for the nodes attribute"""
code = parse("Have a {{template}}")
self.assertEqual(["Have a ", "{{template}}"], code.nodes)
assert ["Have a " == "{{template}}"], code.nodes
L1 = SmartList([Text("foobar"), Template(wraptext("abc"))])
L2 = [Text("barfoo"), Template(wraptext("cba"))]
L3 = "abc{{def}}"
code.nodes = L1
self.assertIs(L1, code.nodes)
assert L1 is code.nodes
code.nodes = L2
self.assertIs(L2, code.nodes)
assert L2 is code.nodes
code.nodes = L3
self.assertEqual(["abc", "{{def}}"], code.nodes)
self.assertRaises(ValueError, setattr, code, "nodes", object)
assert ["abc" == "{{def}}"], code.nodes
with pytest.raises(ValueError):
code.__setattr__("nodes", object)

def test_get(self):
"""test Wikicode.get()"""
code = parse("Have a {{template}} and a [[page|link]]")
self.assertIs(code.nodes[0], code.get(0))
self.assertIs(code.nodes[2], code.get(2))
self.assertRaises(IndexError, code.get, 4)
assert code.nodes[0] is code.get(0)
assert code.nodes[2] is code.get(2)
with pytest.raises(IndexError):
code.get(4)

def test_set(self):
"""test Wikicode.set()"""
code = parse("Have a {{template}} and a [[page|link]]")
code.set(1, "{{{argument}}}")
self.assertEqual("Have a {{{argument}}} and a [[page|link]]", code)
self.assertIsInstance(code.get(1), Argument)
assert "Have a {{{argument}}} and a [[page|link]]" == code
assert isinstance(code.get(1), Argument)
code.set(2, None)
self.assertEqual("Have a {{{argument}}}[[page|link]]", code)
assert "Have a {{{argument}}}[[page|link]]" == code
code.set(-3, "This is an ")
self.assertEqual("This is an {{{argument}}}[[page|link]]", code)
self.assertRaises(ValueError, code.set, 1, "foo {{bar}}")
self.assertRaises(IndexError, code.set, 3, "{{baz}}")
self.assertRaises(IndexError, code.set, -4, "{{baz}}")
assert "This is an {{{argument}}}[[page|link]]" == code
with pytest.raises(ValueError):
code.set(1, "foo {{bar}}")
with pytest.raises(IndexError):
code.set(3, "{{baz}}")
with pytest.raises(IndexError):
code.set(-4, "{{baz}}")

def test_contains(self):
"""test Wikicode.contains()"""
code = parse("Here is {{aaa|{{bbb|xyz{{ccc}}}}}} and a [[page|link]]")
tmpl1, tmpl2, tmpl3 = code.filter_templates()
tmpl4 = parse("{{ccc}}").filter_templates()[0]
self.assertTrue(code.contains(tmpl1))
self.assertTrue(code.contains(tmpl3))
self.assertFalse(code.contains(tmpl4))
self.assertTrue(code.contains(str(tmpl4)))
self.assertTrue(code.contains(tmpl2.params[0].value))
assert code.contains(tmpl1) is True
assert code.contains(tmpl3) is True
assert code.contains(tmpl4) is False
assert code.contains(str(tmpl4)) is True
assert code.contains(tmpl2.params[0].value) is True

def test_index(self):
"""test Wikicode.index()"""
code = parse("Have a {{template}} and a [[page|link]]")
self.assertEqual(0, code.index("Have a "))
self.assertEqual(3, code.index("[[page|link]]"))
self.assertEqual(1, code.index(code.get(1)))
self.assertRaises(ValueError, code.index, "foo")
assert 0 == code.index("Have a ")
assert 3 == code.index("[[page|link]]")
assert 1 == code.index(code.get(1))
with pytest.raises(ValueError):
code.index("foo")

code = parse("{{foo}}{{bar|{{baz}}}}")
self.assertEqual(1, code.index("{{bar|{{baz}}}}"))
self.assertEqual(1, code.index("{{baz}}", recursive=True))
self.assertEqual(1, code.index(code.get(1).get(1).value,
recursive=True))
self.assertRaises(ValueError, code.index, "{{baz}}", recursive=False)
self.assertRaises(ValueError, code.index,
code.get(1).get(1).value, recursive=False)
assert 1 == code.index("{{bar|{{baz}}}}")
assert 1 == code.index("{{baz}}", recursive=True)
assert 1 == code.index(code.get(1).get(1).value,
recursive=True)
with pytest.raises(ValueError):
code.index("{{baz}}", recursive=False)
with pytest.raises(ValueError):
code.index(code.get(1).get(1).value, recursive=False)

def test_get_ancestors_parent(self):
"""test Wikicode.get_ancestors() and Wikicode.get_parent()"""
@@ -115,37 +121,36 @@ class TestWikicode(TreeEqualityTestCase):
parent3 = code.filter_templates(matches=lambda n: n.name == "a")[0]
fake = parse("{{f}}").get(0)

self.assertEqual([parent3, parent2, parent1], code.get_ancestors(tmpl))
self.assertIs(parent1, code.get_parent(tmpl))
self.assertEqual([], code.get_ancestors(parent3))
self.assertIs(None, code.get_parent(parent3))
self.assertRaises(ValueError, code.get_ancestors, fake)
self.assertRaises(ValueError, code.get_parent, fake)
assert [parent3 == parent2, parent1], code.get_ancestors(tmpl)
assert parent1 is code.get_parent(tmpl)
assert [] == code.get_ancestors(parent3)
assert None is code.get_parent(parent3)
with pytest.raises(ValueError):
code.get_ancestors(fake)
with pytest.raises(ValueError):
code.get_parent(fake)

def test_insert(self):
"""test Wikicode.insert()"""
code = parse("Have a {{template}} and a [[page|link]]")
code.insert(1, "{{{argument}}}")
self.assertEqual(
"Have a {{{argument}}}{{template}} and a [[page|link]]", code)
self.assertIsInstance(code.get(1), Argument)
assert "Have a {{{argument}}}{{template}} and a [[page|link]]" == code
assert isinstance(code.get(1), Argument)
code.insert(2, None)
self.assertEqual(
"Have a {{{argument}}}{{template}} and a [[page|link]]", code)
assert "Have a {{{argument}}}{{template}} and a [[page|link]]" == code
code.insert(-3, Text("foo"))
self.assertEqual(
"Have a {{{argument}}}foo{{template}} and a [[page|link]]", code)
assert "Have a {{{argument}}}foo{{template}} and a [[page|link]]" == code

code2 = parse("{{foo}}{{bar}}{{baz}}")
code2.insert(1, "abc{{def}}ghi[[jk]]")
self.assertEqual("{{foo}}abc{{def}}ghi[[jk]]{{bar}}{{baz}}", code2)
self.assertEqual(["{{foo}}", "abc", "{{def}}", "ghi", "[[jk]]",
"{{bar}}", "{{baz}}"], code2.nodes)
assert "{{foo}}abc{{def}}ghi[[jk]]{{bar}}{{baz}}" == code2
assert ["{{foo}}", "abc", "{{def}}", "ghi", "[[jk]]",
"{{bar}}", "{{baz}}"] == code2.nodes

code3 = parse("{{foo}}bar")
code3.insert(1000, "[[baz]]")
code3.insert(-1000, "derp")
self.assertEqual("derp{{foo}}bar[[baz]]", code3)
assert "derp{{foo}}bar[[baz]]" == code3

def _test_search(self, meth, expected):
"""Base test for insert_before(), insert_after(), and replace()."""
@@ -154,12 +159,16 @@ class TestWikicode(TreeEqualityTestCase):
func("{{b}}", "x", recursive=True)
func("{{d}}", "[[y]]", recursive=False)
func(code.get(2), "z")
self.assertEqual(expected[0], code)
self.assertRaises(ValueError, func, "{{r}}", "n", recursive=True)
self.assertRaises(ValueError, func, "{{r}}", "n", recursive=False)
assert expected[0] == code
with pytest.raises(ValueError):
func("{{r}}", "n", recursive=True)
with pytest.raises(ValueError):
func("{{r}}", "n", recursive=False)
fake = parse("{{a}}").get(0)
self.assertRaises(ValueError, func, fake, "n", recursive=True)
self.assertRaises(ValueError, func, fake, "n", recursive=False)
with pytest.raises(ValueError):
func(fake, "n", recursive=True)
with pytest.raises(ValueError):
func(fake, "n", recursive=False)

code2 = parse("{{a}}{{a}}{{a}}{{b}}{{b}}{{b}}")
func = partial(meth, code2)
@@ -167,67 +176,78 @@ class TestWikicode(TreeEqualityTestCase):
func("{{a}}", "d", recursive=False)
func(code2.get(-1), "e", recursive=True)
func("{{b}}", "f", recursive=True)
self.assertEqual(expected[1], code2)
assert expected[1] == code2

code3 = parse("{{a|{{b}}|{{c|d={{f}}}}}}")
func = partial(meth, code3)
obj = code3.get(0).params[0].value.get(0)
self.assertRaises(ValueError, func, obj, "x", recursive=False)
with pytest.raises(ValueError):
func(obj, "x", recursive=False)
func(obj, "x", recursive=True)
self.assertRaises(ValueError, func, "{{f}}", "y", recursive=False)
with pytest.raises(ValueError):
func("{{f}}", "y", recursive=False)
func("{{f}}", "y", recursive=True)
self.assertEqual(expected[2], code3)
assert expected[2] == code3

code4 = parse("{{a}}{{b}}{{c}}{{d}}{{e}}{{f}}{{g}}{{h}}{{i}}{{j}}")
func = partial(meth, code4)
fake = parse("{{b}}{{c}}")
self.assertRaises(ValueError, func, fake, "q", recursive=False)
self.assertRaises(ValueError, func, fake, "q", recursive=True)
with pytest.raises(ValueError):
func(fake, "q", recursive=False)
with pytest.raises(ValueError):
func(fake, "q", recursive=True)
func("{{b}}{{c}}", "w", recursive=False)
func("{{d}}{{e}}", "x", recursive=True)
func(Wikicode(code4.nodes[-2:]), "y", recursive=False)
func(Wikicode(code4.nodes[-2:]), "z", recursive=True)
self.assertEqual(expected[3], code4)
self.assertRaises(ValueError, func, "{{c}}{{d}}", "q", recursive=False)
self.assertRaises(ValueError, func, "{{c}}{{d}}", "q", recursive=True)
assert expected[3] == code4
with pytest.raises(ValueError):
func("{{c}}{{d}}", "q", recursive=False)
with pytest.raises(ValueError):
func("{{c}}{{d}}", "q", recursive=True)

code5 = parse("{{a|{{b}}{{c}}|{{f|{{g}}={{h}}{{i}}}}}}")
func = partial(meth, code5)
self.assertRaises(ValueError, func, "{{b}}{{c}}", "x", recursive=False)
with pytest.raises(ValueError):
func("{{b}}{{c}}", "x", recursive=False)
func("{{b}}{{c}}", "x", recursive=True)
obj = code5.get(0).params[1].value.get(0).params[0].value
self.assertRaises(ValueError, func, obj, "y", recursive=False)
with pytest.raises(ValueError):
func(obj, "y", recursive=False)
func(obj, "y", recursive=True)
self.assertEqual(expected[4], code5)
assert expected[4] == code5

code6 = parse("here is {{some text and a {{template}}}}")
func = partial(meth, code6)
self.assertRaises(ValueError, func, "text and", "ab", recursive=False)
with pytest.raises(ValueError):
func("text and", "ab", recursive=False)
func("text and", "ab", recursive=True)
self.assertRaises(ValueError, func, "is {{some", "cd", recursive=False)
with pytest.raises(ValueError):
func("is {{some", "cd", recursive=False)
func("is {{some", "cd", recursive=True)
self.assertEqual(expected[5], code6)
assert expected[5] == code6

code7 = parse("{{foo}}{{bar}}{{baz}}{{foo}}{{baz}}")
func = partial(meth, code7)
obj = wrap([code7.get(0), code7.get(2)])
self.assertRaises(ValueError, func, obj, "{{lol}}")
with pytest.raises(ValueError):
func(obj, "{{lol}}")
func("{{foo}}{{baz}}", "{{lol}}")
self.assertEqual(expected[6], code7)
assert expected[6] == code7

code8 = parse("== header ==")
func = partial(meth, code8)
sec1, sec2 = code8.get_sections(include_headings=False)
func(sec1, "lead\n")
func(sec2, "\nbody")
self.assertEqual(expected[7], code8)
assert expected[7] == code8

code9 = parse("{{foo}}")
meth(code9.get_sections()[0], code9.get_sections()[0], "{{bar}}")
meth(code9.get_sections()[0], code9, "{{baz}}")
meth(code9, code9, "{{qux}}")
meth(code9, code9.get_sections()[0], "{{quz}}")
self.assertEqual(expected[8], code9)
assert expected[8] == code9

def test_insert_before(self):
"""test Wikicode.insert_before()"""
@@ -281,13 +301,14 @@ class TestWikicode(TreeEqualityTestCase):
"""test Wikicode.append()"""
code = parse("Have a {{template}}")
code.append("{{{argument}}}")
self.assertEqual("Have a {{template}}{{{argument}}}", code)
self.assertIsInstance(code.get(2), Argument)
assert "Have a {{template}}{{{argument}}}" == code
assert isinstance(code.get(2), Argument)
code.append(None)
self.assertEqual("Have a {{template}}{{{argument}}}", code)
assert "Have a {{template}}{{{argument}}}" == code
code.append(Text(" foo"))
self.assertEqual("Have a {{template}}{{{argument}}} foo", code)
self.assertRaises(ValueError, code.append, slice(0, 1))
assert "Have a {{template}}{{{argument}}} foo" == code
with pytest.raises(ValueError):
code.append(slice(0, 1))

def test_remove(self):
"""test Wikicode.remove()"""
@@ -312,109 +333,112 @@ class TestWikicode(TreeEqualityTestCase):
code3 = parse("Hello world!")
code4 = parse("World,_hello?")
code5 = parse("")
self.assertTrue(code1.matches("Cleanup"))
self.assertTrue(code1.matches("cleanup"))
self.assertTrue(code1.matches(" cleanup\n"))
self.assertFalse(code1.matches("CLEANup"))
self.assertFalse(code1.matches("Blah"))
self.assertTrue(code2.matches("stub"))
self.assertTrue(code2.matches("Stub<!-- no, it's fine! -->"))
self.assertFalse(code2.matches("StuB"))
self.assertTrue(code1.matches(("cleanup", "stub")))
self.assertTrue(code2.matches(("cleanup", "stub")))
self.assertFalse(code2.matches(("StuB", "sTUb", "foobar")))
self.assertFalse(code2.matches(["StuB", "sTUb", "foobar"]))
self.assertTrue(code2.matches(("StuB", "sTUb", "foo", "bar", "Stub")))
self.assertTrue(code2.matches(["StuB", "sTUb", "foo", "bar", "Stub"]))
self.assertTrue(code3.matches("hello world!"))
self.assertTrue(code3.matches("hello_world!"))
self.assertFalse(code3.matches("hello__world!"))
self.assertTrue(code4.matches("World,_hello?"))
self.assertTrue(code4.matches("World, hello?"))
self.assertFalse(code4.matches("World, hello?"))
self.assertTrue(code5.matches(""))
self.assertTrue(code5.matches("<!-- nothing -->"))
self.assertTrue(code5.matches(("a", "b", "")))
assert code1.matches("Cleanup") is True
assert code1.matches("cleanup") is True
assert code1.matches(" cleanup\n") is True
assert code1.matches("CLEANup") is False
assert code1.matches("Blah") is False
assert code2.matches("stub") is True
assert code2.matches("Stub<!-- no, it's fine! -->") is True
assert code2.matches("StuB") is False
assert code1.matches(("cleanup", "stub")) is True
assert code2.matches(("cleanup", "stub")) is True
assert code2.matches(("StuB", "sTUb", "foobar")) is False
assert code2.matches(["StuB", "sTUb", "foobar"]) is False
assert code2.matches(("StuB", "sTUb", "foo", "bar", "Stub")) is True
assert code2.matches(["StuB", "sTUb", "foo", "bar", "Stub"]) is True
assert code3.matches("hello world!") is True
assert code3.matches("hello_world!") is True
assert code3.matches("hello__world!") is False
assert code4.matches("World,_hello?") is True
assert code4.matches("World, hello?") is True
assert code4.matches("World, hello?") is False
assert code5.matches("") is True
assert code5.matches("<!-- nothing -->") is True
assert code5.matches(("a", "b", "")) is True

def test_filter_family(self):
"""test the Wikicode.i?filter() family of functions"""
def genlist(gen):
self.assertIsInstance(gen, GeneratorType)
assert isinstance(gen, GeneratorType)
return list(gen)
ifilter = lambda code: (lambda *a, **k: genlist(code.ifilter(*a, **k)))

code = parse("a{{b}}c[[d]]{{{e}}}{{f}}[[g]]")
for func in (code.filter, ifilter(code)):
self.assertEqual(["a", "{{b}}", "b", "c", "[[d]]", "d", "{{{e}}}",
"e", "{{f}}", "f", "[[g]]", "g"], func())
self.assertEqual(["{{{e}}}"], func(forcetype=Argument))
self.assertIs(code.get(4), func(forcetype=Argument)[0])
self.assertEqual(list("abcdefg"), func(forcetype=Text))
self.assertEqual([], func(forcetype=Heading))
self.assertRaises(TypeError, func, forcetype=True)
assert ["a", "{{b}}", "b", "c", "[[d]]", "d", "{{{e}}}",
"e", "{{f}}", "f", "[[g]]", "g"] == func()
assert ["{{{e}}}"] == func(forcetype=Argument)
assert code.get(4) is func(forcetype=Argument)[0]
assert list("abcdefg") == func(forcetype=Text)
assert [] == func(forcetype=Heading)
with pytest.raises(TypeError):
func(forcetype=True)

funcs = [
lambda name, **kw: getattr(code, "filter_" + name)(**kw),
lambda name, **kw: genlist(getattr(code, "ifilter_" + name)(**kw))
]
for get_filter in funcs:
self.assertEqual(["{{{e}}}"], get_filter("arguments"))
self.assertIs(code.get(4), get_filter("arguments")[0])
self.assertEqual([], get_filter("comments"))
self.assertEqual([], get_filter("external_links"))
self.assertEqual([], get_filter("headings"))
self.assertEqual([], get_filter("html_entities"))
self.assertEqual([], get_filter("tags"))
self.assertEqual(["{{b}}", "{{f}}"], get_filter("templates"))
self.assertEqual(list("abcdefg"), get_filter("text"))
self.assertEqual(["[[d]]", "[[g]]"], get_filter("wikilinks"))
assert ["{{{e}}}"] == get_filter("arguments")
assert code.get(4) is get_filter("arguments")[0]
assert [] == get_filter("comments")
assert [] == get_filter("external_links")
assert [] == get_filter("headings")
assert [] == get_filter("html_entities")
assert [] == get_filter("tags")
assert ["{{b}}" == "{{f}}"], get_filter("templates")
assert list("abcdefg") == get_filter("text")
assert ["[[d]]" == "[[g]]"], get_filter("wikilinks")

code2 = parse("{{a|{{b}}|{{c|d={{f}}{{h}}}}}}")
for func in (code2.filter, ifilter(code2)):
self.assertEqual(["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}"],
func(recursive=False, forcetype=Template))
self.assertEqual(["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}", "{{b}}",
"{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"],
func(recursive=True, forcetype=Template))
assert ["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}"] \
== func(recursive=False, forcetype=Template)
assert ["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}", "{{b}}",
"{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"] \
== func(recursive=True, forcetype=Template)

code3 = parse("{{foobar}}{{FOO}}{{baz}}{{bz}}{{barfoo}}")
for func in (code3.filter, ifilter(code3)):
self.assertEqual(["{{foobar}}", "{{barfoo}}"],
func(False, matches=lambda node: "foo" in node))
self.assertEqual(["{{foobar}}", "{{FOO}}", "{{barfoo}}"],
func(False, matches=r"foo"))
self.assertEqual(["{{foobar}}", "{{FOO}}"],
func(matches=r"^{{foo.*?}}"))
self.assertEqual(["{{foobar}}"],
func(matches=r"^{{foo.*?}}", flags=re.UNICODE))
self.assertEqual(["{{baz}}", "{{bz}}"], func(matches=r"^{{b.*?z"))
self.assertEqual(["{{baz}}"], func(matches=r"^{{b.+?z}}"))
assert ["{{foobar}}", "{{barfoo}}"] \
== func(False, matches=lambda node: "foo" in node)
assert ["{{foobar}}", "{{FOO}}", "{{barfoo}}"] \
== func(False, matches=r"foo")
assert ["{{foobar}}", "{{FOO}}"] \
== func(matches=r"^{{foo.*?}}")
assert ["{{foobar}}"] \
== func(matches=r"^{{foo.*?}}", flags=re.UNICODE)
assert ["{{baz}}" == "{{bz}}"], func(matches=r"^{{b.*?z")
assert ["{{baz}}"] == func(matches=r"^{{b.+?z}}")

exp_rec = ["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}", "{{b}}",
"{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"]
"{{c|d={{f}}{{h}}}}", "{{f}}", "{{h}}"]
exp_unrec = ["{{a|{{b}}|{{c|d={{f}}{{h}}}}}}"]
self.assertEqual(exp_rec, code2.filter_templates())
self.assertEqual(exp_unrec, code2.filter_templates(recursive=False))
self.assertEqual(exp_rec, code2.filter_templates(recursive=True))
self.assertEqual(exp_rec, code2.filter_templates(True))
self.assertEqual(exp_unrec, code2.filter_templates(False))

self.assertEqual(["{{foobar}}"], code3.filter_templates(
matches=lambda node: node.name.matches("Foobar")))
self.assertEqual(["{{baz}}", "{{bz}}"],
code3.filter_templates(matches=r"^{{b.*?z"))
self.assertEqual([], code3.filter_tags(matches=r"^{{b.*?z"))
self.assertEqual([], code3.filter_tags(matches=r"^{{b.*?z", flags=0))

self.assertRaises(TypeError, code.filter_templates, a=42)
self.assertRaises(TypeError, code.filter_templates, forcetype=Template)
self.assertRaises(TypeError, code.filter_templates, 1, 0, 0, Template)
assert exp_rec == code2.filter_templates()
assert exp_unrec == code2.filter_templates(recursive=False)
assert exp_rec == code2.filter_templates(recursive=True)
assert exp_rec == code2.filter_templates(True)
assert exp_unrec == code2.filter_templates(False)

assert ["{{foobar}}"] == code3.filter_templates(
matches=lambda node: node.name.matches("Foobar"))
assert ["{{baz}}", "{{bz}}"] \
== code3.filter_templates(matches=r"^{{b.*?z")
assert [] == code3.filter_tags(matches=r"^{{b.*?z")
assert [] == code3.filter_tags(matches=r"^{{b.*?z", flags=0)
with pytest.raises(TypeError):
code.filter_templates(a=42)
with pytest.raises(TypeError):
code.filter_templates(forcetype=Template)
with pytest.raises(TypeError):
code.filter_templates(1, 0, 0, Template)

code4 = parse("{{foo}}<b>{{foo|{{bar}}}}</b>")
actual1 = code4.filter_templates(recursive=code4.RECURSE_OTHERS)
actual2 = code4.filter_templates(code4.RECURSE_OTHERS)
self.assertEqual(["{{foo}}", "{{foo|{{bar}}}}"], actual1)
self.assertEqual(["{{foo}}", "{{foo|{{bar}}}}"], actual2)
assert ["{{foo}}" == "{{foo|{{bar}}}}"], actual1
assert ["{{foo}}" == "{{foo|{{bar}}}}"], actual2

def test_get_sections(self):
"""test Wikicode.get_sections()"""
@@ -435,78 +459,75 @@ class TestWikicode(TreeEqualityTestCase):
p4_III = "== Section III ==\n" + p4_IIIA
page4 = parse(p4_lead + p4_I + p4_II + p4_III)

self.assertEqual([""], page1.get_sections())
self.assertEqual(["", "==Heading=="], page2.get_sections())
self.assertEqual(["", "===Heading===\nFoo bar baz\n====Gnidaeh====\n",
"====Gnidaeh====\n"], page3.get_sections())
self.assertEqual([p4_lead, p4_I, p4_IA, p4_IB, p4_IB1, p4_II,
p4_III, p4_IIIA, p4_IIIA1a, p4_IIIA2, p4_IIIA2ai1],
page4.get_sections())

self.assertEqual(["====Gnidaeh====\n"], page3.get_sections(levels=[4]))
self.assertEqual(["===Heading===\nFoo bar baz\n====Gnidaeh====\n"],
page3.get_sections(levels=(2, 3)))
self.assertEqual(["===Heading===\nFoo bar baz\n"],
page3.get_sections(levels=(2, 3), flat=True))
self.assertEqual([], page3.get_sections(levels=[0]))
self.assertEqual(["", "====Gnidaeh====\n"],
page3.get_sections(levels=[4], include_lead=True))
self.assertEqual(["===Heading===\nFoo bar baz\n====Gnidaeh====\n",
"====Gnidaeh====\n"],
page3.get_sections(include_lead=False))
self.assertEqual(["===Heading===\nFoo bar baz\n", "====Gnidaeh====\n"],
page3.get_sections(flat=True, include_lead=False))

self.assertEqual([p4_IB1, p4_IIIA2], page4.get_sections(levels=[4]))
self.assertEqual([p4_IA, p4_IB, p4_IIIA], page4.get_sections(levels=[3]))
self.assertEqual([p4_IA, "=== Section I.B ===\n",
"=== Section III.A ===\nText.\n"],
page4.get_sections(levels=[3], flat=True))
self.assertEqual(["", ""], page2.get_sections(include_headings=False))
self.assertEqual(["\nSection I.B.1 body.\n\n&bull;Some content.\n\n",
"\nEven more text.\n" + p4_IIIA2ai1],
page4.get_sections(levels=[4],
include_headings=False))

self.assertEqual([], page4.get_sections(matches=r"body"))
self.assertEqual([p4_I, p4_IA, p4_IB, p4_IB1],
page4.get_sections(matches=r"Section\sI[.\s].*?"))
self.assertEqual([p4_IA, p4_IIIA, p4_IIIA1a, p4_IIIA2, p4_IIIA2ai1],
page4.get_sections(matches=r".*?a.*?"))
self.assertEqual([p4_IIIA1a, p4_IIIA2ai1],
page4.get_sections(matches=r".*?a.*?", flags=re.U))
self.assertEqual(["\nMore text.\n", "\nAn invalid section!"],
page4.get_sections(matches=r".*?a.*?", flags=re.U,
include_headings=False))
assert [""] == page1.get_sections()
assert ["" == "==Heading=="], page2.get_sections()
assert ["", "===Heading===\nFoo bar baz\n====Gnidaeh====\n", "====Gnidaeh====\n"] \
== page3.get_sections()
assert [p4_lead, p4_I, p4_IA, p4_IB, p4_IB1, p4_II,
p4_III, p4_IIIA, p4_IIIA1a, p4_IIIA2, p4_IIIA2ai1] \
== page4.get_sections()

assert ["====Gnidaeh====\n"] == page3.get_sections(levels=[4])
assert ["===Heading===\nFoo bar baz\n====Gnidaeh====\n"] \
== page3.get_sections(levels=(2, 3))
assert ["===Heading===\nFoo bar baz\n"] \
== page3.get_sections(levels=(2, 3), flat=True)
assert [] == page3.get_sections(levels=[0])
assert ["", "====Gnidaeh====\n"] == page3.get_sections(levels=[4], include_lead=True)
assert ["===Heading===\nFoo bar baz\n====Gnidaeh====\n",
"====Gnidaeh====\n"] == page3.get_sections(include_lead=False)
assert ["===Heading===\nFoo bar baz\n", "====Gnidaeh====\n"] \
== page3.get_sections(flat=True, include_lead=False)

assert [p4_IB1 == p4_IIIA2], page4.get_sections(levels=[4])
assert [p4_IA == p4_IB, p4_IIIA], page4.get_sections(levels=[3])
assert [p4_IA, "=== Section I.B ===\n",
"=== Section III.A ===\nText.\n"] \
== page4.get_sections(levels=[3], flat=True)
assert ["" == ""], page2.get_sections(include_headings=False)
assert ["\nSection I.B.1 body.\n\n&bull;Some content.\n\n",
"\nEven more text.\n" + p4_IIIA2ai1] \
== page4.get_sections(levels=[4], include_headings=False)

assert [] == page4.get_sections(matches=r"body")
assert [p4_I, p4_IA, p4_IB, p4_IB1] \
== page4.get_sections(matches=r"Section\sI[.\s].*?")
assert [p4_IA, p4_IIIA, p4_IIIA1a, p4_IIIA2, p4_IIIA2ai1] \
== page4.get_sections(matches=r".*?a.*?")
assert [p4_IIIA1a, p4_IIIA2ai1] \
== page4.get_sections(matches=r".*?a.*?", flags=re.U)
assert ["\nMore text.\n", "\nAn invalid section!"] \
== page4.get_sections(matches=r".*?a.*?", flags=re.U,
include_headings=False)

sections = page2.get_sections(include_headings=False)
sections[0].append("Lead!\n")
sections[1].append("\nFirst section!")
self.assertEqual("Lead!\n==Heading==\nFirst section!", page2)
assert "Lead!\n==Heading==\nFirst section!" == page2

page5 = parse("X\n== Foo ==\nBar\n== Baz ==\nBuzz")
section = page5.get_sections(matches="Foo")[0]
section.replace("\nBar\n", "\nBarf ")
section.append("{{Haha}}\n")
self.assertEqual("== Foo ==\nBarf {{Haha}}\n", section)
self.assertEqual("X\n== Foo ==\nBarf {{Haha}}\n== Baz ==\nBuzz", page5)
assert "== Foo ==\nBarf {{Haha}}\n" == section
assert "X\n== Foo ==\nBarf {{Haha}}\n== Baz ==\nBuzz" == page5

def test_strip_code(self):
"""test Wikicode.strip_code()"""
# Since individual nodes have test cases for their __strip__ methods,
# we're only going to do an integration test:
code = parse("Foo [[bar]]\n\n{{baz|hello}}\n\n[[a|b]] &Sigma;")
self.assertEqual("Foo bar\n\nb Σ",
code.strip_code(normalize=True, collapse=True))
self.assertEqual("Foo bar\n\n\n\nb Σ",
code.strip_code(normalize=True, collapse=False))
self.assertEqual("Foo bar\n\nb &Sigma;",
code.strip_code(normalize=False, collapse=True))
self.assertEqual("Foo bar\n\n\n\nb &Sigma;",
code.strip_code(normalize=False, collapse=False))
self.assertEqual("Foo bar\n\nhello\n\nb Σ",
code.strip_code(normalize=True, collapse=True,
keep_template_params=True))
assert "Foo bar\n\nb Σ" \
== code.strip_code(normalize=True, collapse=True)
assert "Foo bar\n\n\n\nb Σ" \
== code.strip_code(normalize=True, collapse=False)
assert "Foo bar\n\nb &Sigma;" \
== code.strip_code(normalize=False, collapse=True)
assert "Foo bar\n\n\n\nb &Sigma;" \
== code.strip_code(normalize=False, collapse=False)
assert "Foo bar\n\nhello\n\nb Σ" \
== code.strip_code(normalize=True, collapse=True,
keep_template_params=True)

def test_get_tree(self):
"""test Wikicode.get_tree()"""
@@ -516,7 +537,4 @@ class TestWikicode(TreeEqualityTestCase):
code = parse("Lorem ipsum {{foo|bar|{{baz}}|spam=eggs}}")
expected = "Lorem ipsum \n{{\n\t foo\n\t| 1\n\t= bar\n\t| 2\n\t= " + \
"{{\n\t\t\tbaz\n\t }}\n\t| spam\n\t= eggs\n}}"
self.assertEqual(expected.expandtabs(4), code.get_tree())

if __name__ == "__main__":
unittest.main(verbosity=2)
assert expected.expandtabs(4) == code.get_tree()

+ 18
- 19
tests/test_wikilink.py View File

@@ -19,7 +19,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import unittest
import pytest

from mwparserfromhell.nodes import Text, Wikilink

@@ -31,9 +31,9 @@ class TestWikilink(TreeEqualityTestCase):
def test_unicode(self):
"""test Wikilink.__unicode__()"""
node = Wikilink(wraptext("foobar"))
self.assertEqual("[[foobar]]", str(node))
assert "[[foobar]]" == str(node)
node2 = Wikilink(wraptext("foo"), wraptext("bar"))
self.assertEqual("[[foo|bar]]", str(node2))
assert "[[foo|bar]]" == str(node2)

def test_children(self):
"""test Wikilink.__children__()"""
@@ -41,18 +41,20 @@ class TestWikilink(TreeEqualityTestCase):
node2 = Wikilink(wraptext("foo"), wrap([Text("bar"), Text("baz")]))
gen1 = node1.__children__()
gen2 = node2.__children__()
self.assertEqual(node1.title, next(gen1))
self.assertEqual(node2.title, next(gen2))
self.assertEqual(node2.text, next(gen2))
self.assertRaises(StopIteration, next, gen1)
self.assertRaises(StopIteration, next, gen2)
assert node1.title == next(gen1)
assert node2.title == next(gen2)
assert node2.text == next(gen2)
with pytest.raises(StopIteration):
next(gen1)
with pytest.raises(StopIteration):
next(gen2)

def test_strip(self):
"""test Wikilink.__strip__()"""
node = Wikilink(wraptext("foobar"))
node2 = Wikilink(wraptext("foo"), wraptext("bar"))
self.assertEqual("foobar", node.__strip__())
self.assertEqual("bar", node2.__strip__())
assert "foobar" == node.__strip__()
assert "bar" == node2.__strip__()

def test_showtree(self):
"""test Wikilink.__showtree__()"""
@@ -67,15 +69,15 @@ class TestWikilink(TreeEqualityTestCase):
valid = [
"[[", (getter, node1.title), "]]", "[[", (getter, node2.title),
" | ", marker, (getter, node2.text), "]]"]
self.assertEqual(valid, output)
assert 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)
assert title is node1.title
assert title is node2.title
node1.title = "héhehé"
node2.title = "héhehé"
self.assertWikicodeEqual(wraptext("héhehé"), node1.title)
@@ -86,12 +88,9 @@ class TestWikilink(TreeEqualityTestCase):
text = wraptext("baz")
node1 = Wikilink(wraptext("foobar"))
node2 = Wikilink(wraptext("foobar"), text)
self.assertIs(None, node1.text)
self.assertIs(text, node2.text)
assert None is node1.text
assert text is 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)
assert None is node2.text

Loading…
Cancel
Save