import os, string, cStringIO

from xml.dom import Node
from Ft.Lib import Uri
from Ft.Xml import ReaderException, Domlette, InputSource
from Ft.Xml.Lib import TreeCompare

g_has_pyxml = False
try:
    from xml.dom import ext
    g_has_pyxml = True
except ImportError:
    pass

# Py 2.2 doesn't have UnicodeEncodeError
try:
    UnicodeEncodeError
except NameError:
    UnicodeEncodeError = None

BASE_PATH = os.path.dirname(os.path.abspath(__file__))
BASE_PATH = Uri.OsPathToUri(BASE_PATH, attemptAbsolute=True) + '/'

def CompareXml(expected, compared):
    try:
        rv = TreeCompare.TreeCompare(expected, compared, baseUri=BASE_PATH)
        return rv
    except Exception, e:
        import traceback
        traceback.print_exc()
        return 1

def CompareXmlNode(expected, compared, ignoreComments=0):
    try:
        rv = TreeCompare.NodeCompare(expected, compared, ignoreComments=ignoreComments)
        return rv
    except Exception, e:
        import traceback
        traceback.print_exc()
        return 1

def can_validate(dom_module):
    # cDomlette doesn't support validation natively
    return g_has_pyxml

def test_reader(tester,domMod):
    tester.startGroup("DOM Readers")
    test_validating_reader(tester, domMod)
    test_nonvalidating_reader(tester, domMod)
    test_xml_base(tester, domMod)
    test_extent_xinclude(tester, domMod)
    test_strip_elements(tester, domMod)
    test_namespaces(tester, domMod)
    test_read_utf16(tester, domMod)
    test_encoding_override(tester, domMod)
    test_read_exceptions(tester, domMod.NonvalParse)
    test_various_docs(tester, domMod)
    tester.groupDone()
    return

def test_oasis_suite(tester, domMod):
    test_suite_root_var = 'W3C_XMLTS_ROOT'
    tester.startGroup("W3C XML Conformance Test Suites (XML TS)")
    if not os.environ.has_key(test_suite_root_var):
        tester.warning('Not tested; set %s to point to the'
                       ' xmlconf directory.' % test_suite_root_var)
        tester.groupDone()
        return
    else:
        XMLTS_BASE = os.environ[test_suite_root_var]

    if not os.path.isfile(os.path.join(XMLTS_BASE, 'xmlconf.xml')):
        tester.warning('Not tested; directory %s does not seem to'
                       ' contain the W3C XML Conformance Test Suite'
                       ' XML TS files.' % test_suite_root_var)
        tester.groupDone()
        return

    tester.startGroup("James Clark's XML Test Cases (1998-11-18)")
    # (casedir, casename, use validating parser?, expect exception?)
    JCLARK_CASES = [ ('not-wf', 'Not well-formed', 0, 1),
                     ('valid', 'Valid', 1, 0),
                     ('invalid', 'Invalid', 1, 1),
                   ]
    JCLARK_SUBCASES = [ ('sa', 'Standalone; no ext. general entity refs'),
                        ('ext-sa', 'Standalone; w/ ext. general entity refs'),
                        ('not-sa', 'Not standalone'),
                      ]
    TESTS_TO_SKIP = {
                      ('valid', 'sa', '012.xml'): 'only OK in non-namespace-aware system',
                    }

    # not-wf/not-sa/005.xml, although documented as testing a VC, should
    #  actually first fail on an obscure WFC. However, exactly what the
    #  expected error is seems to be something known only to a non-public
    #  W3C group. See the discussion at
    # http://lists.w3.org/Archives/Public/public-xml-testsuite/2002Jun/0018.html
    # http://lists.w3.org/Archives/Public/public-xml-testsuite/2002Jun/0022.html
    #
    # not-wf/not-sa/010.xml and not-wf/not-sa/011.xml
    # are supposed to fail "WFC: PE Between Declarations"
    # according to this message:
    # http://lists.w3.org/Archives/Public/public-xml-testsuite/2002Jun/0018.html
    #
    nonval_only = not can_validate(domMod)
    for casedir, casename, validating, exc_expected in JCLARK_CASES:
        if validating and nonval_only:
            tester.startGroup(casename)
            tester.warning("You need PyXML to run tests that require a validating parser")
            tester.groupDone()
            break
        for subcasedir, subcasename in JCLARK_SUBCASES:
            DIR = os.path.join(XMLTS_BASE, 'xmltest', casedir, subcasedir)
            if os.path.isdir(DIR):
                tester.startGroup('%s; %s' % (casename, subcasename))
                XML_FILENAMES = filter(lambda f: f.endswith('.xml'), os.listdir(DIR))
                XML_FILENAMES.sort()
                for filename in XML_FILENAMES:
                    tester.startTest(filename)
                    skipkey = (casedir, subcasedir, filename)
                    if TESTS_TO_SKIP.has_key(skipkey):
                        tester.warning('Not tested; %s' % TESTS_TO_SKIP[skipkey])
                    else:
                        XML_FILEPATH = os.path.join(DIR, filename)
                        uri = Uri.OsPathToUri(XML_FILEPATH)
                        isrc = InputSource.DefaultFactory.fromUri(uri)
                        if validating:
                            if exc_expected:
                                tester.testException(domMod.ValParse,
                                                     (isrc,),
                                                     ReaderException,
                                                     {'errorCode': ReaderException.XML_PARSE_ERROR}
                                                     )
                            else:
                                try:
                                    dom = domMod.ValParse(isrc)
                                except ReaderException:
                                    tester.exception('The validating reader raised an unexpected exception.')
                                else:
                                    # The document parsed without exceptions, so
                                    # now let's check the parsed document against the
                                    # parsed Canonical XML equivalent, if available
                                    CXML_FILEPATH = os.path.join(DIR, 'out', filename)
                                    if os.path.isfile(CXML_FILEPATH):
                                        curi = Uri.OsPathToUri(CXML_FILEPATH)
                                        cisrc = InputSource.DefaultFactory.fromUri(curi)
                                        try:
                                            cdom = domMod.NonvalParse(cisrc)
                                        except ReaderException:
                                            tester.exception('The nonvalidating reader raised an unexpected exception.')
                                        else:
                                            if not CompareXmlNode(cdom, dom, ignoreComments=1):
                                                tester.error('The validating reader parsed the document incorrectly.')

                        else:
                            if exc_expected:
                                tester.testException(domMod.NonvalParse,
                                                     (isrc,),
                                                     ReaderException,
                                                     {'errorCode': ReaderException.XML_PARSE_ERROR}
                                                     )
                            else:
                                try:
                                    dom = domMod.NonvalParse(isrc)
                                except ReaderException:
                                    tester.exception('The nonvalidating reader raised an unexpected exception.')

                    tester.testDone()
                tester.groupDone()

    tester.groupDone() # James Clark's XML Test Cases

    tester.startGroup("SUN Microsystems XML test cases")
    tester.warning("Not tested.")
    tester.groupDone() # SUN

    tester.startGroup("OASIS XML test cases")
    tester.warning("Not tested.")
    tester.groupDone() # OASIS

    tester.startGroup("Fuji Xerox XML test cases")
    tester.warning("Not tested.")
    tester.groupDone() # Fuji Xerox

    tester.groupDone() # OASIS XML Test Suite

def test_read_utf16(tester,domMod):
    tester.startGroup("Read UTF-16")

    tester.startTest("Good XML: UTF-16LE, LE BOM, utf-16 encoding declaration")
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'goodXml_16LE_LEBOM_16Decl.xml')
    dom = domMod.NonvalParse(isrc)
    tester.testDone()

    tester.startTest("Good XML: UTF-16BE, BE BOM, utf-16 encoding declaration")
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'goodXml_16BE_BEBOM_16Decl.xml')
    dom = domMod.NonvalParse(isrc)
    tester.testDone()

    tester.startTest("Good XML: UTF-16LE, LE BOM, no encoding declaration")
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'goodXml_16LE_LEBOM_noDecl.xml')
    dom = domMod.NonvalParse(isrc)
    tester.testDone()

    tester.startTest("Good XML: UTF-16BE, BE BOM, no encoding declaration")
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'goodXml_16BE_BEBOM_noDecl.xml')
    dom = domMod.NonvalParse(isrc)
    tester.testDone()

    tester.startTest("Bad XML: UTF-16LE, BE BOM, utf-16 encoding declaration")
    # A big-endian BOM will result in little-endian prolog being interpreted as
    # Chinese characters, resulting in a well-formedness error because there
    # is no document element
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'badXml_16LE_BEBOM_16Decl.xml')
    tester.testException(domMod.NonvalParse,
                         (isrc,),
                         ReaderException,
                         {'errorCode': ReaderException.XML_PARSE_ERROR}
                         )
    tester.testDone()

    tester.startTest("Bad XML: UTF-16LE, LE BOM, utf-16le encoding declaration")
    # by definition, utf-16le and utf-16be do not have a BOM. if a little-endian
    # BOM is encountered, it is interpreted as a zero-width no-break space, which
    # is not allowed at the beginning of an XML document entity.
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'badXml_16LE_LEBOM_16LEDecl.xml')
##    tester.testException(domMod.NonvalParse,
##                         (isrc,),
##                         ReaderException,
##                         {'errorCode': ReaderException.XML_PARSE_ERROR}
##                         )
    tester.warning("This does not throw an exception") # why not?
    tester.testDone()

    tester.startTest("Bad XML: UTF-16LE, no BOM, utf-16 encoding declaration")
    # if the encoding declaration is "utf-16", a BOM is required. without a BOM,
    # UTF-8 will be assumed initially, so the 0x00 bytes will be interpreted as
    # U+0000, which is not allowed in an XML document
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'badXml_16LE_noBOM_16Decl.xml')
##    tester.testException(domMod.NonvalParse,
##                         (isrc,),
##                         ReaderException,
##                         {'errorCode': ReaderException.XML_PARSE_ERROR}
##                         )
    tester.warning("This does not throw an exception") # why not?
    tester.testDone()

    tester.startTest("Bad XML: UTF-8, no BOM, utf-16 encoding declaration")
    # if the encoding declaration is "utf-16", a BOM is required. without a BOM,
    # UTF-8 will be assumed initially, so the xml declaration is readable, but
    # when the "utf-16" is encountered, a fatal error must occur because there
    # is no BOM. if the parser doesn't catch this error, it should then have a
    # well-formedness error because there is no document element, only a string
    # of non-Latin characters
    isrc = InputSource.DefaultFactory.fromUri(BASE_PATH + 'badXml_utf8_noBOM_16Decl.xml')
    tester.testException(domMod.NonvalParse,
                         (isrc,),
                         ReaderException,
                         {'errorCode': ReaderException.XML_PARSE_ERROR}
                         )
    tester.testDone()

    tester.groupDone()
    return


def test_encoding_override(tester, domMod):
    tester.startGroup("External encoding declaration")
    for actual_enc in ('utf-8', 'iso-8859-1', 'us-ascii', 'utf-16'):
        for declared_enc in ('utf-8', 'iso-8859-1', 'us-ascii', 'utf-16', 'x-klingon'):
            tester.startTest('declared internally: %s; externally/actual: %s' % (declared_enc, actual_enc))
            src = JGREETING_UNICODE % declared_enc
            try:
                src = src.encode(actual_enc)
            except (UnicodeError, UnicodeEncodeError):
                src = JGREETING_ESCAPED % declared_enc
                src = src.encode(actual_enc)

            isrc = InputSource.DefaultFactory.fromString(src, 'http://4suite.org/jgreeting.xml', encoding=actual_enc)
            doc = domMod.NonvalParse(isrc)
            chars = doc.documentElement.firstChild.data
            tester.compare(u'\u4eca\u65e5\u306f', chars)
            tester.testDone()
    tester.groupDone()


def test_strip_elements(tester,domMod):
    tester.startGroup("Strip Elements")

    tester.startTest("Strip Elements")
    src = "<ft:foo xmlns:ft='http://fourthought.com' xmlns:ft2='http://foo.com'><ft:bar>  </ft:bar><ft:bar> F </ft:bar><ft:baz>  Bar1  </ft:baz><ft2:bar>  </ft2:bar><ft2:baz> Bar2 </ft2:baz><bar>  </bar><baz>  Bar3  </baz></ft:foo>"

    stripElements = [(None,'bar',1),
                     ('http://fourthought.com','bar',1),
                     ('http://foo.com','*',1)]

    isrc = InputSource.DefaultFactory.fromString(src, BASE_PATH,
                                                 stripElements=stripElements)
    dom = domMod.NonvalParse(isrc)

    tester.compare(None,dom.documentElement.childNodes[0].firstChild)
    tester.compare(" F ",dom.documentElement.childNodes[1].firstChild.data)
    tester.compare("  Bar1  ",dom.documentElement.childNodes[2].firstChild.data)
    tester.compare(None,dom.documentElement.childNodes[3].firstChild)
    tester.compare(" Bar2 ",dom.documentElement.childNodes[4].firstChild.data)
    tester.compare(None,dom.documentElement.childNodes[5].firstChild)
    tester.compare("  Bar3  ",dom.documentElement.childNodes[6].firstChild.data)
    tester.testDone()

    tester.startTest("Strip Elements with xml:space")
    src = """\
<svg xml:space="preserve" width="1000" height="1000"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <desc>Salary Chart</desc>
  <g style='stroke:#000000;stroke-width:1;font-family:Arial;font-size:16'>
    <xsl:for-each select="ROWSET/ROW">
      <xsl:call-template name="drawBar" xml:space="default">
        <xsl:with-param name="rowIndex" select="position()"/>
        <xsl:with-param name="ename" select="ENAME"/>
        <xsl:with-param name="sal" select="number(SAL)"/>
      </xsl:call-template>
    </xsl:for-each>
  </g>
</svg>"""

    expected = """<?xml version="1.0" encoding="UTF-8"?>
<svg xml:space="preserve" width="1000" height="1000"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <desc>Salary Chart</desc>
  <g style='stroke:#000000;stroke-width:1;font-family:Arial;font-size:16'>
    <xsl:for-each select="ROWSET/ROW">
      <xsl:call-template name="drawBar" xml:space="default"><xsl:with-param name="rowIndex" select="position()"/><xsl:with-param name="ename" select="ENAME"/><xsl:with-param name="sal" select="number(SAL)"/></xsl:call-template>
    </xsl:for-each>
  </g>
</svg>"""

    src = """<?xml version="1.0" encoding="UTF-8"?>
<element xml:space="preserve">
  <element>
    <!-- surrounding WS should be preserved -->
  </element>
</element>"""

    stripElements = [(None, '*', True)]

    isrc = InputSource.DefaultFactory.fromString(src, BASE_PATH,
                                                 stripElements=stripElements)
    dom = domMod.NonvalParse(isrc)
    sio = cStringIO.StringIO()
    Domlette.Print(dom, sio)
    actual = sio.getvalue()
    tester.compare(src, actual, func=TreeCompare.TreeCompare)
    tester.testDone()

    tester.groupDone()
    return


def test_xml_base(tester, domMod):
    tester.startGroup("XML Base")

    tester.startTest("xml-base")
    src = BASE_TEST

    #strip all ws, set document base URI
    isrc = InputSource.DefaultFactory.fromString(src,"http://rdfInference.org",stripElements=[(None, '*', 1)])
    dom = domMod.NonvalParse(isrc)

    tester.compare("http://rdfInference.org", dom.baseURI)
    tester.compare("http://rdfInference.org", dom.documentElement.baseURI)
    tester.compare("http://fourthought.com", dom.documentElement.firstChild.baseURI)
    #monty
    tester.compare("http://fourthought.com", dom.documentElement.firstChild.firstChild.baseURI)
    #knight
    tester.compare("http://fourthought.com", dom.documentElement.firstChild.firstChild.firstChild.baseURI)
    #foo
    tester.compare("http://4suite.org", dom.documentElement.firstChild.childNodes[1].baseURI)
    #foobar
    tester.compare("http://4suite.org", dom.documentElement.firstChild.childNodes[1].firstChild.baseURI)

    tester.testDone()

    tester.groupDone()
    return


def test_validating_reader(tester,domMod):
    tester.startGroup("Validating Reader")

    tester.startTest("Read Valid Document")
    if can_validate(domMod):
        source_1 = ADDRBOOK
        isrc = InputSource.DefaultFactory.fromString(source_1, BASE_PATH)
        dom = domMod.ValParse(isrc)
        if dom.documentElement:
            tester.compare('ADDRBOOK', dom.documentElement.localName)
        else:
            tester.error("Validating parser returned an empty document")
    else:
        tester.warning("You need PyXML installed to test the validating parser")
    tester.testDone()

    tester.startTest("Read Invalid Document")

    if can_validate(domMod):
        source_1 = ADDRBOOK_INVALID
        isrc = InputSource.DefaultFactory.fromString(source_1, BASE_PATH)
        tester.testException(domMod.ValParse,(isrc,),ReaderException)
    else:
        tester.warning("You need PyXML installed to test the validating parser")
    tester.testDone()


    tester.groupDone()
    return


def test_nonvalidating_reader(tester,domMod):
    tester.startGroup("non-Validating Reader")


    tester.startTest("Simple XML")
    src = InputSource.DefaultFactory.fromString(SMALL_XML, BASE_PATH)
    doc = domMod.NonvalParse(src)

    #Test a few of the nodes
    tester.compare(2,len(doc.childNodes))
    tester.compare(Node.PROCESSING_INSTRUCTION_NODE,doc.childNodes[0].nodeType)
    tester.compare("xml-stylesheet",doc.childNodes[0].target)
    tester.compare('href="addr_book1.xsl" type="text/xml"',doc.childNodes[0].data)

    tester.compare(Node.ELEMENT_NODE,doc.childNodes[1].nodeType)
    tester.compare('docelem',doc.childNodes[1].nodeName)
    tester.compare(None,doc.childNodes[1].namespaceURI)
    tester.compare(None,doc.childNodes[1].prefix)
    tester.compare(doc.childNodes[1],doc.documentElement)
    tester.compare(9,len(doc.documentElement.childNodes))

    tester.compare(1,len(doc.documentElement.attributes.keys()))
    tester.compare(('http://www.w3.org/2000/xmlns/', 'ft'),doc.documentElement.attributes.keys()[0])
    tester.compare('http://fourthought.com',doc.documentElement.attributes.values()[0].value)

    tester.compare(1,len(doc.documentElement.childNodes[1].attributes.keys()))
    tester.compare((None,'foo'),doc.documentElement.childNodes[1].attributes.keys()[0])
    tester.compare('bar',doc.documentElement.childNodes[1].attributes.values()[0].value)
    tester.compare('Some Text',doc.documentElement.childNodes[1].childNodes[0].data)


    tester.compare('http://fourthought.com',doc.documentElement.childNodes[5].namespaceURI)
    tester.compare('ft',doc.documentElement.childNodes[5].prefix)
    tester.compare(1,len(doc.documentElement.childNodes[5].attributes.keys()))
    tester.compare(('http://fourthought.com','foo'),doc.documentElement.childNodes[5].attributes.keys()[0])
    tester.compare('nsbar',doc.documentElement.childNodes[5].attributes.values()[0].value)
    tester.testDone()

##    tester.startTest("Parse XML containing undeclared namespace prefix (should be OK)")
##    src = InputSource.DefaultFactory.fromString(QNAME_NO_NSDECL, BASE_PATH)
##    doc = domMod.NonvalParse(src)
##    tester.testDone()
##    tester.groupDone()

    tester.startTest("Parse nasty XML")
    src = InputSource.DefaultFactory.fromString(LARGE_XML, BASE_PATH)
    doc = domMod.NonvalParse(src)
    tester.testDone()

    tester.startTest("Document with general entity defined in external subset (parse method 1)")
    source_1 = GREETING
    isrc = InputSource.DefaultFactory.fromString(source_1, BASE_PATH)
    dom = domMod.NonvalParse(isrc, readExtDtd=1)
    stream = cStringIO.StringIO()
    Domlette.Print(dom, stream)
    expected_1 = """\
<?xml version="1.0" encoding="UTF-8"?>
<greeting>hello world</greeting>
"""
    tester.compare(expected_1, stream.getvalue(), func=CompareXml)
    tester.testDone()

    # same as previous test but going through Ft.Xml.Domlette
    tester.startTest("Document with general entity defined in external subset (parse method 2)")
    source_1 = GREETING
    isrc = InputSource.DefaultFactory.fromString(source_1, BASE_PATH)
    from Ft.Xml.Domlette import NonvalidatingReaderBase
    reader = NonvalidatingReaderBase()
    reader.kwargs['readExtDtd'] = 1
    dom = reader.parse(isrc)
    stream = cStringIO.StringIO()
    Domlette.Print(dom, stream)
    expected_1 = """\
<?xml version="1.0" encoding="UTF-8"?>
<greeting>hello world</greeting>
"""
    tester.compare(expected_1, stream.getvalue(), func=CompareXml)
    tester.testDone()
    tester.groupDone()


def test_read_exceptions(tester,parseMethod):
    tester.startGroup("Reader exceptions")

    tester.startTest("Basic Parse Exception")
    tester.warning("Not Tested")
##    tester.testException(reader.fromString,
##                         (BASE_PATH,),
##                         ReaderException,
##                         {'errorCode': ReaderException.XML_PARSE_ERROR}
##                         )
    tester.testDone()


    tester.groupDone()


def test_namespaces(tester,domMod):
    expected = [(None,'xmlns','http://www.w3.org/2000/xmlns/'),
                ('xmlns','are','http://www.w3.org/2000/xmlns/'),
                ('xmlns','foo','http://www.w3.org/2000/xmlns/'),
                ]

    src="""<?xml version="1.0"?>
<diamonds xmlns:are="urn:forever" xmlns:foo="urn:bar" xmlns="http://nowhere"/>"""



    tester.startGroup("Namespaces")

    tester.startTest("Simple test")

    isrc = InputSource.DefaultFactory.fromString(src, BASE_PATH)
    doc = domMod.NonvalParse(isrc)
    attrs = doc.documentElement.attributes.values()
    attrs.sort(lambda a, b: cmp(a.name, b.name))
    tester.compare(3,len(attrs))
    for attr in attrs:
        test = (attr.prefix,attr.localName,attr.namespaceURI)
        tester.compareIn(expected,test)
    tester.testDone()
    tester.groupDone()
    return


def test_extent_xinclude(tester, domMod):
    tester.startGroup("Reader + External Entities + XInclude")

    SRC_1 = """\
<?xml version='1.0'?>
<!DOCTYPE x [ <!ENTITY inc SYSTEM "include1.xml"> ]>
<x>
&inc;
</x>"""
    expected_1="""<?xml version='1.0' encoding='UTF-8'?><x>

<foo/>
</x>"""
    tester.startTest("External entity")

    src = InputSource.DefaultFactory.fromString(SRC_1, BASE_PATH)

    doc = domMod.NonvalParse(src)
    stream = cStringIO.StringIO()
    Domlette.Print(doc, stream)
    tester.compare(expected_1, stream.getvalue(), func=TreeCompare.TreeCompare)
    tester.testDone()

    SRC_2 = """\
<?xml version='1.0'?>
<x xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="include1.xml"/>
</x>"""

    expected_2 = """<?xml version='1.0' encoding='UTF-8'?>
<x xmlns:xi='http://www.w3.org/2001/XInclude'>
<foo/>
</x>"""
    tester.startTest("Basic XInclude")
    src = InputSource.DefaultFactory.fromString(SRC_2, BASE_PATH)
    doc = domMod.NonvalParse(src)
    stream = cStringIO.StringIO()
    Domlette.Print(doc, stream)
    tester.compare(expected_2, stream.getvalue(), func=TreeCompare.NoWsTreeCompare)
    tester.testDone()

    SRC_3="""\
<?xml version='1.0'?>
<x xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="include2.xml"/>
</x>"""
    expected_3="""<?xml version='1.0' encoding='UTF-8'?>
<x xmlns:xi='http://www.w3.org/2001/XInclude'>
<foo>
  <foo/>
</foo>
</x>
"""
    tester.startTest("Recursive XInclude")
    src = InputSource.DefaultFactory.fromString(SRC_3, BASE_PATH)
    doc = domMod.NonvalParse(src)
    stream = cStringIO.StringIO()
    Domlette.Print(doc, stream)
    tester.compare(expected_3, stream.getvalue(), func=TreeCompare.NoWsTreeCompare)
    tester.testDone()

    SRC_4="""\
<?xml version='1.0'?>
<x xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="include2.xml" parse='text'/>
</x>"""
    from test_xinclude import LINESEP
    expected_4="""<?xml version='1.0' encoding='UTF-8'?>
<x xmlns:xi='http://www.w3.org/2001/XInclude'>
&lt;?xml version='1.0' encoding='utf-8'?>%(linesep)s&lt;foo xmlns:xi="http://www.w3.org/2001/XInclude">%(linesep)s  &lt;xi:include href="include1.xml"/>%(linesep)s&lt;/foo>
</x>
""" % {'linesep' : LINESEP}

    tester.startTest("XInclude text attribute")
    src = InputSource.DefaultFactory.fromString(SRC_4, BASE_PATH)
    doc = domMod.NonvalParse(src)
    stream = cStringIO.StringIO()
    Domlette.Print(doc, stream)
    tester.compare(expected_4, stream.getvalue(),func = TreeCompare.TreeCompare)
    tester.testDone()

    tester.groupDone()
    return

def test_various_docs(tester, domMod):

    def test_one_str(count, content, exception, tester=tester, module=domMod):
        tester.startTest("Document %d non-validating" % count)
        src = InputSource.DefaultFactory.fromString(content, BASE_PATH)
        if exception:
            tester.testException(module.NonvalParse, (src, ),
                                 ReaderException)
        else:
            doc = module.NonvalParse(src)
            stream = cStringIO.StringIO()
            Domlette.Print(doc, stream)
            tester.compare(content, stream.getvalue(), func=CompareXml)
        tester.testDone()

        tester.startTest("Document %d validating" % count)
        if can_validate(module):
            src = InputSource.DefaultFactory.fromString(content, BASE_PATH)
            if exception:
                tester.testException(module.NonvalParse, (src, ),
                                     ReaderException)
            else:
                doc = module.ValParse(src)
                stream = cStringIO.StringIO()
                Domlette.Print(doc, stream)
                tester.compare(content, stream.getvalue(), func=CompareXml)
        else:
            tester.warning("You need PyXML installed to test the validating "
                           "parser")
        tester.testDone()
        return

    def test_one_uri(count, uri, exception, tester=tester, module=domMod):
        tester.startTest("Document %d non-validating" % count)
        src = InputSource.DefaultFactory.fromUri(uri, BASE_PATH)
        if exception:
            tester.testException(module.NonvalParse, (src, ),
                                 ReaderException)
        else:
            doc = module.NonvalParse(src)
            stream = cStringIO.StringIO()
            Domlette.Print(doc, stream)
            src = InputSource.DefaultFactory.fromUri(uri, BASE_PATH)
            tester.compare(src.read(), stream.getvalue(), func=CompareXml)
        tester.testDone()

        tester.startTest("Document %d validating" % count)
        if can_validate(module):
            src = InputSource.DefaultFactory.fromUri(uri, BASE_PATH)
            if exception:
                tester.testException(module.NonvalParse, (src, ),
                                     ReaderException)
            else:
                doc = module.ValParse(src)
                stream = cStringIO.StringIO()
                Domlette.Print(doc, stream)
                src = InputSource.DefaultFactory.fromUri(uri, BASE_PATH)
                tester.compare(src.read(), stream.getvalue(), func=CompareXml)
        else:
            tester.warning("You need PyXML installed to test the validating "
                           "parser")
        tester.testDone()
        return

    tester.startGroup("Simple round trip of various XML (as strings)")
    count = 1
    for string in VARIOUS_STRINGS:
        test_one_str(count, string, 0)
        count += 1
    tester.groupDone()


    tester.startGroup("Simple round trip of various XML (as files)")
    count = 1
    for uri in VARIOUS_FILES:
        test_one_uri(count, uri, 0)
        count += 1
    tester.groupDone()

    tester.startGroup("Simple round trip of various bad XML (as strings)")
    count = 1
    for string in VARIOUS_STRINGS_BAD:
        test_one_str(count, string, 1)
        count += 1
    tester.groupDone()


    tester.startGroup("Simple round trip of various bad XML (as files)")
    count = 1
    for uri in VARIOUS_FILES_BAD:
        test_one_uri(count, uri, 1)
        count += 1
    tester.groupDone()
    return


QNAME_NO_NSDECL = """<?xml version="1.0"?>
<docelem>
  <somePrefix:city>Boulder</somePrefix:city>
</docelem>
"""

SMALL_XML = """<?xml version = "1.0"?>
<?xml-stylesheet href="addr_book1.xsl" type="text/xml"?>
<docelem xmlns:ft='http://fourthought.com'>
  <child foo='bar'>Some Text</child>
  <!--A comment-->
  <ft:nschild ft:foo='nsbar'>Some More Text</ft:nschild>
  <appendChild/>
</docelem>
"""



LARGE_XML="""<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="../../style/function.use-cases.xsl"?>
<!-- <!DOCTYPE exslt:function SYSTEM 'function.dtd'> -->
<exslt:function xmlns:exslt="http://exslt.org/documentation"
                version="1" module="math" status="new">

<exslt:name>min</exslt:name>

<rdf:Description xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
                 xmlns:dc="http://purl.org/dc/elements/1.1/"
                 ID="math:min">
   <dc:subject>EXSLT</dc:subject>
   <dc:subject>math</dc:subject>
   <dc:subject>min</dc:subject>
   <dc:subject>minimum</dc:subject>
   <dc:rights>public domain</dc:rights>
   <exslt:revision>
      <rdf:Description xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
                       xmlns:dc="http://purl.org/dc/elements/1.1/"
                       ID="math:min.1">
         <exslt:version>1</exslt:version>
         <dc:creator email="mail@jenitennison.com"
                     url="http://www.jenitennison.com">Jeni Tennison</dc:creator>
         <dc:date>2001-03-28</dc:date>
         <dc:description>Returns the minimum value from a node-set.</dc:description>
      </rdf:Description>
   </exslt:revision>
</rdf:Description>

<exslt:doc xmlns="">
   <section>
      <para>
         The <function>math:min</function> function returns the minimum, for each node in the argument node-set, of the result of converting the string-values of the node to a number using the <ulink URL='http://www.w3.org/TR/xpath#function-number'> <function>number</function></ulink> function.  The numbers are compared as with the <literal>&lt;</literal> operator.  If the node set is empty, <returnvalue>NaN</returnvalue> is returned.
      </para>
      <para>
         The <literal>math:min</literal> template returns a result tree fragment whose string value is the result of turning the number returned by the function into a string.
      </para>
   </section>
</exslt:doc>

<exslt:definition>
   <exslt:return type="number" />
   <exslt:arg name="nodes" type="node-set" default="/.." />
</exslt:definition>

<exslt:implementations>
   <exslt:implementation src="math.min.function.xsl" language="exslt:exslt"
                         version="1" />
   <exslt:implementation src="math.min.template.xsl" language="exslt:xslt"
                         version="1" />
   <exslt:implementation src="math.min.js" language="javascript"
                         version="1" />
</exslt:implementations>

<exslt:use-cases>
   <exslt:use-case type="example" data="math.min.data.1.xml"
                   xslt="math.min.1.xsl" result="math.min.result.1.xml" />
   <exslt:use-case type="example" template="yes" data="math.min.data.1.xml"
                   xslt="math.min.2.xsl" result="math.min.result.1.xml" />
   <exslt:use-case type="boundary" data="math.min.data.2.xml"
                   xslt="math.min.1.xsl" result="math.min.result.2.xml" />
   <exslt:use-case type="boundary" template="yes" data="math.min.data.2.xml"
                   xslt="math.min.2.xsl" result="math.min.result.2.xml" />
   <exslt:use-case type="error" data="math.min.data.1.xml"
                   xslt="math.min.3.xsl">
      <exslt:doc xmlns="">
         <para>
            This use case shows an error when the function is passed a
            number as the value of the first argument.
         </para>
      </exslt:doc>
   </exslt:use-case>
   <exslt:use-case type="error" template="yes" data="math.min.data.1.xml"
                   xslt="math.min.4.xsl">
      <exslt:doc>
         <para>
            This use case shows an error when the function is passed a
            number as the value of the <parameter>nodes</parameter>
            parameter.
         </para>
      </exslt:doc>
   </exslt:use-case>
</exslt:use-cases>

</exslt:function>"""


GREETING = """<?xml version = "1.0"?>
<!DOCTYPE greeting SYSTEM "greeting.dtd">
<greeting>&bar;</greeting>
"""


JGREETING_UNICODE = u"""<?xml version="1.0" encoding="%s"?>
<greeting xml:lang="ja">\u4eca\u65e5\u306f</greeting>"""

JGREETING_ESCAPED = u"""<?xml version="1.0" encoding="%s"?>
<greeting lang="ja">&#20170;&#26085;&#12399;</greeting>"""


ADDRBOOK = """<?xml version = "1.0"?>
<!DOCTYPE ADDRBOOK SYSTEM "addr_book.dtd">
<ADDRBOOK>
    <ENTRY ID="pa">
        <NAME>Pieter Aaron</NAME>
        <ADDRESS>404 Error Way</ADDRESS>
        <PHONENUM DESC="Work">404-555-1234</PHONENUM>
        <PHONENUM DESC="Fax">404-555-4321</PHONENUM>
        <PHONENUM DESC="Pager">404-555-5555</PHONENUM>
        <EMAIL>pieter.aaron@inter.net</EMAIL>
    </ENTRY>
    <ENTRY ID="en">
        <NAME>Emeka Ndubuisi</NAME>
        <ADDRESS>42 Spam Blvd</ADDRESS>
        <PHONENUM DESC="Work">767-555-7676</PHONENUM>
        <PHONENUM DESC="Fax">767-555-7642</PHONENUM>
        <PHONENUM DESC="Pager">800-SKY-PAGEx767676</PHONENUM>
        <EMAIL>endubuisi@spamtron.com</EMAIL>
    </ENTRY>
    <ENTRY ID="vz">
        <NAME>Vasia Zhugenev</NAME>
        <ADDRESS>2000 Disaster Plaza</ADDRESS>
        <PHONENUM DESC="Work">000-987-6543</PHONENUM>
        <PHONENUM DESC="Cell">000-000-0000</PHONENUM>
        <EMAIL>vxz@magog.ru</EMAIL>
    </ENTRY>
</ADDRBOOK>"""


ADDRBOOK_INVALID = """<?xml version = "1.0"?>
<!DOCTYPE ADDRBOOK SYSTEM "addr_book.dtd">
<ADDRBOOK>
    <INVALIDENTRY ID="pa">
        <NAME>Pieter Aaron</NAME>
        <ADDRESS>404 Error Way</ADDRESS>
        <PHONENUM DESC="Work">404-555-1234</PHONENUM>
        <PHONENUM DESC="Fax">404-555-4321</PHONENUM>
        <PHONENUM DESC="Pager">404-555-5555</PHONENUM>
        <EMAIL>pieter.aaron@inter.net</EMAIL>
    </INVALIDENTRY>
</ADDRBOOK>"""


BASE_TEST = """<?xml version = "1.0"?>
<spam>
  <eggs xml:base="http://fourthought.com">
    <monty python="nicht">knight</monty>
    <foo xml:base="http://4suite.org" bar="baz">foobar</foo>
  </eggs>
</spam>
"""

VARIOUS_STRINGS = [
"""<?xml version="1.0"?>
<!DOCTYPE foo SYSTEM "various_strings_1.dtd">
<foo prefix:bar='' xmlns:prefix='http://spam.org'><prefix:bar/></foo>""",
]

VARIOUS_STRINGS_BAD = [
#XML well-formed but not XMLNS well-formed
"""<?xml version="1.0"?>
<!DOCTYPE foo SYSTEM "various_strings_1.dtd">
<foo undeclared-prefix:bar=''><undeclared-prefix:bar/></foo>""",

# Duplicate attributes
"""<?xml version="1.0" encoding="UTF-8"?>
<vote county="Palm Beach"
      count="23725"
      count="31563"
/>""",

# Duplicate prefixed attributes
"""<?xml version="1.0" encoding="UTF-8"?>
<vote county="Palm Beach"
      r:count="23725"
      d:count="31563"
      dem:count="23293"
      xmlns:dem="http://www.democrat.org/"
      xmlns:d="http://www.democrat.org/"
      xmlns:r="http://www.republican.org/"
/>""",
]

#Place stuff that cannot be in Python files as separate files listed here
VARIOUS_FILES = [
]

VARIOUS_FILES_BAD = [
]
