# -*- coding: utf-8 -*-
# Copyright (C) 2013 Stefan Merten
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
"""
Test XmlParser.
"""
import unittest
import docutils.frontend
from docutils.nodes import Text
from __init__ import DocutilsTestSupport
from docutils_xml.parsers.xml import Uri2Prefixes, XmlVisitor, XmlParser, SomeChildren
###############################################################################
class XmlVisitorMock(XmlVisitor):
"""
Mock class recording calls in document.
"""
depth = 0
"""
:type: int
Current indentation depth.
"""
indent = u" "
"""
:type: unicode
Indentation to use for one step.
"""
currentPrefix = None
"""
:type: str
The prefix of the current call.
"""
currentTag = None
"""
:type: str
The tag of the current call.
"""
def __recordVisit(self, elem):
( pfx, nm ) = self.uri2Prefixes.elem2PrefixName(elem)
attrs = ""
for attr in sorted(elem.keys()):
attrs += " %s=%r" % ( attr, elem.get(attr) )
self.document += Text("%s{ %s:%s%s\n"
% ( self.depth * self.indent,
self.currentPrefix, self.currentTag,
attrs))
self.depth += 1
control = elem.get('control', None)
if control in ( 'SkipNode', 'SkipDeparture', 'SkipSiblings',
'SkipChildren', 'StopTraversal' ):
e = eval("docutils.nodes.%s()" % ( control, ))
try:
raise e
except ( docutils.nodes.SkipNode, docutils.nodes.SkipSiblings ):
self.depth -= 1
raise
elif control == 'SomeChildren':
tags = [ child.split(':', 1)
for child in elem.get('controlSomeChildren', '').split() ]
raise SomeChildren(tags)
return None
def __recordDepart(self, elem):
( pfx, nm ) = self.uri2Prefixes.elem2PrefixName(elem)
self.depth -= 1
self.document += Text("%s} %s:%s\n"
% ( self.depth * self.indent,
self.currentPrefix, self.currentTag ))
return None
def __getattr__(self, name):
( currentType, self.currentPrefix,
self.currentTag ) = name.split('_', 2)
if currentType == 'visit':
return self.__recordVisit
else:
return self.__recordDepart
###############################################################################
class XmlParserMock(XmlParser):
"""
Mock class recording visited nodes in the output document.
"""
uri2Prefixes = Uri2Prefixes((
( 'urn:example', 'ex', 'alias', 'int' ),
# ( 'urn:empty', u'' ), # Empty tag is not accepted by lxml
( 'urn:other', 'ot' ),
))
visitorClass = XmlVisitorMock
###############################################################################
class XmlParserTestCase(DocutilsTestSupport.ParserTestCase):
"""
Output checker for XmlParser.
Supports additional settings on input and exceptions on output as
`XsltParserTestCase` does.
"""
parser = XmlParserMock()
"""Parser shared by all XmlParserTestCases."""
option_parser = docutils.frontend.OptionParser(components=(
XmlParserMock, ))
def test_parser(self):
if self.run_in_debugger:
pdb.set_trace()
if isinstance(self.input, ( list, tuple )):
( case_settings, input ) = self.input
else:
( case_settings, input ) = ( { }, self.input )
settings = self.settings.copy()
settings.__dict__.update(self.suite_settings)
settings.__dict__.update(case_settings)
document = docutils.utils.new_document('test data', settings)
if (isinstance(self.expected, type)
and issubclass(self.expected, Exception)):
with self.assertRaises(self.expected):
self.parser.parse(input, document)
else:
self.parser.parse(input, document)
output = document.pformat()
self.compare_output(input, output, self.expected)
###############################################################################
class XmlParserTestSuite(DocutilsTestSupport.ParserTestSuite):
test_case_class = XmlParserTestCase
###############################################################################
totest = {}
totest['simple'] = (
( u"""
""",
"""
{ :rootOnly
} :rootOnly
""" ),
( u"""
""",
"""
{ :root
{ :embedded
} :embedded
} :root
""" ),
( u"""
""",
"""
{ :root
{ :one
} :one
{ :two
} :two
} :root
""" ),
( u"""
""",
"""
{ :rootOnly attribute='content' otherAttr='moreContent'
} :rootOnly
""" ),
)
totest['nonAscii'] = (
( u"""
""",
"""
{ :rootmlaut
} :rootmlaut
""" ),
)
totest['encoding'] = (
( """
""",
"""
{ :rootOnly
} :rootOnly
""" ),
( """
""",
"""
{ :rootOnly
} :rootOnly
""" ),
( u"""
""",
"""
{ :rootOnly
} :rootOnly
""" ),
( """
""",
"""
{ :rootOnly
} :rootOnly
""" ),
( u"""
""",
"""
{ :rootOnly
} :rootOnly
""" ),
( """
""",
u"""
{ :rootmlaut
} :rootmlaut
""" ),
( u"""
""",
u"""
{ :rootmlaut
} :rootmlaut
""" ),
( u"""
""",
LookupError ),
( u"""
""",
UnicodeError ),
)
totest['namespace'] = (
( u"""
""",
"""
{ :root
{ ex:one
} ex:one
{ ex:two
} ex:two
{ ot:three
} ot:three
} :root
""" ),
)
totest['SkipNode'] = (
( u"""
""",
"""
{ :root control='SkipNode'
""" ),
)
totest['SkipDeparture'] = (
( u"""
""",
"""
{ :root control='SkipDeparture'
{ :one
} :one
{ :two
} :two
""" ),
)
totest['SkipSiblings'] = (
( u"""
""",
"""
{ :root
{ :one control='SkipSiblings'
} :root
""" ),
)
totest['SkipChildren'] = (
( u"""
""",
"""
{ :root control='SkipChildren'
} :root
""" ),
)
totest['StopTraversal'] = (
( u"""
""",
"""
{ :root
{ :one control='StopTraversal'
} :one
} :root
""" ),
)
totest['SomeChildren'] = (
# Take care to use namespaced children
( u"""
""",
"""
{ :root control='SomeChildren'
} :root
""" ),
( u"""
""",
"""
{ :root control='SomeChildren' controlSomeChildren='ex:one'
{ ex:one
} ex:one
} :root
""" ),
( u"""
""",
"""
{ :root control='SomeChildren' controlSomeChildren='ex:one ex:two ex:three'
{ ex:one
} ex:one
{ ex:two
} ex:two
} :root
""" ),
)
###############################################################################
def suite():
s = XmlParserTestSuite()
s.generateTests(totest)
return s
###############################################################################
if __name__ == '__main__':
import unittest
unittest.main(defaultTest='suite')