#!/usr/bin/python
"""
$Id: validity.py,v 1.17 2007/06/14 12:51:21 dom Exp $

The ValidityTestCase implements the validator.testcase.TestCase
interface for the tests related to the following BP:
* Create documents that validate to published formal grammars. 

License
-------
Copyright (c) 2006 World Wide Web Consortium, (Massachusetts
Institute of Technology, European Research Consortium for Informatics
and Mathematics, Keio University). All Rights Reserved. This work is
distributed under the W3C Software License [1] 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.

[1] http://www.w3.org/Consortium/Legal/copyright-software

"""


from  validator import testcase 

from xml.parsers.xmlproc.xmlapp import ErrorHandler
class CatalogErrorHandler(ErrorHandler):
    def error(self,msg):
        pass

class XMLErrorHandler(ErrorHandler):
    def __init__(self,locator):
        ErrorHandler.__init__(self,locator)
        self._observations = TestResults()
    
    def error(self,msg):
        locator = self.get_locator()
        location = testcase.LineColumnLocation(locator.get_current_sysid(),"utf-8",locator.get_line(),locator.get_column())
        self._observations.append(testcase.Observation("VA3",location,{"msg":msg}))

    def fatal(self,msg):
        locator = self.get_locator()
        location = testcase.LineColumnLocation(locator.get_current_sysid(),"utf-8",locator.get_line(),locator.get_column())
        if msg[0:len("character set conversion problem :'utf8'")]=="character set conversion problem: 'utf8'":
            msg = u"The encoding of the page is assumed to be UTF8, but it isn't. Make sure the proper encoding is declared in the Content-Type header or in the XML declaration"
        self._observations.append(testcase.Observation("VA2",location,{"msg":msg}))

    def getObservations(self):
        return self._observations

# Tests regarding the VALID_MARKUP BP
class ValidityTestCase(testcase.URIBasedTestCase):
    BpId = ["VALID_MARKUP"]

    def run(self,uri):
        # should this be implemented using the SOAP interface of the validator?
        # @@@
        self.uri=uri
        self._observations = TestResults()
        from xml.parsers.xmlproc import xmlproc
        from xml.parsers.xmlproc import xmlval, catalog
        from xml.parsers.xmlproc import xmldtd
        # needs to be a configuration option@@@
        catalog_path = "/usr/local/share/sgml-lib/"
        #catalog_path = "/home/dom/dev.w3.org/validator/htdocs/sgml-lib/"
        
        # we use the inputsourcefactory system to
        # use our own HTTP dereferencing (e.g. with caching)
        # file:///usr/share/doc/python2.3-xml/xmlproc/xmlproc-doco.html#InputSourceFactory
        class ISF(xmlval.InputSourceFactory):
            def create_input_source(self,sysid):
                if len(sysid) > 7 and sysid[:7]=="file://":
                    ospath = sysid[7:]
                    if ospath[:len(catalog_path)]==catalog_path:
                        return open(sysid[7:])
                    else:
                        return None
                from validator.utils import HTTPRequest
                from StringIO import StringIO
                h = HTTPRequest()
                headers,content = h.http_request(sysid)
                return StringIO(content)

        # in mobileOK we check that your content is valid
        # with regard to the XHTML Basic 1.1 DTD, no matter the declared
        # doctype
        dtd = xmldtd.load_dtd('http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd')
        # dtd2 = xmldtd.load_dtd('http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd')
        p = xmlval.XMLProcessor()
        p.set_application(xmlval.ValidatingApp(dtd, p))
        p.ent = dtd
        
        # xml.soc comes from
        # http://dev.w3.org/cvsweb/validator/htdocs/sgml-lib/xml.soc
        cat=catalog.xmlproc_catalog("file://" + catalog_path + "xml.soc",catalog.CatParserFactory(),CatalogErrorHandler(p))
        err = XMLErrorHandler(p)
        p.set_error_handler(err)
        p.set_pubid_resolver(cat)
        p.set_inputsource_factory(ISF())
        # @@@ Should find a better way, but I don't know how to
        # catch non-XML doctypes yet
        try:
            p.parse_resource(uri)
            for o in err.getObservations():
                self.addObservation(o)
        except:
            self.addObservation(testcase.Observation("VA2",testcase.Location(self.uri),{'msg':"The doctype used is not recognized as an XML doctype."}))
        if "VA2" in self._observations:
            self.addObservation(testcase.Observation("VA4",testcase.Location(self.uri)))
        elif "VA3" in self._observations:
            self.addObservation(testcase.Observation("VA5",testcase.Location(self.uri)))
        else:
            self.addObservation(testcase.Observation("VA1",testcase.Location(self.uri)))
        return self._observations

# -------------------------
# Unit tests for this module
import unittest

from validator.testcase import TestResults, Observation, Location, LineColumnLocation
class Tests(unittest.TestCase):
    def _test(self,inp,res):
        a = ValidityTestCase()
        self.assertEqual(a.run(inp),res)
        
    def testValid(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/base.xhtml"
        res = TestResults(
            [Observation("VA1",Location(inp))]
            )
        self._test(inp,res)

    def testValidWithNonBasicDoctype(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/nonBasic.xhtml"
        res = TestResults(
            [Observation("VA1",Location(inp))]
            )
        self._test(inp,res)

    # If this fails, it is likely that you need to apply the patch to xmlproc
    # given at http://sourceforge.net/tracker/index.php?func=detail&aid=802617&group_id=6473&atid=106473
    # def testWellFormed(self):
      # inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/wf.xhtml"
      # res = TestResults(
      #       [Observation('VA1',Location(inp))])
      # self._test(inp,res)


    def testWellFormedEmptyDoctype(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/nodoctype.xhtml"
        res = TestResults(
            [Observation("VA5",Location(inp))]
            )
        self._test(inp,res)
    

    def testNonWellFormed(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/nonwf.xhtml"
        res = TestResults(
            [Observation('VA3',LineColumnLocation(inp,'utf-8',13,10),{'msg': u"Element 'address' not allowed here"}),
             Observation('VA2',LineColumnLocation(inp,'utf-8',16,8),{'msg': u"End tag for 'body' seen, but 'p' expected"}),
             Observation('VA2',LineColumnLocation(inp,'utf-8',17,8),{'msg': u"End tag for 'html' seen, but 'p' expected"}),
             Observation('VA2',LineColumnLocation(inp,'utf-8',17,8),{'msg': u"Premature document end, element 'p' not closed"}),
             Observation("VA4",Location(inp))])
        self._test(inp,res)

#     def testHTML401(self):
#         inp = "http://t-mobile.de/"
#         res = TestResults(
#              [Observation('VA3',Location(inp),{'msg':"The doctype used is not recognized as an XML doctype."}),
#               Observation("VA4",Location(inp))])
#         self._test(inp,res)

    def testXHTMLMP(self):
         inp = "http://www.shamrock.de/pda"
         res = TestResults(
              [Observation('VA1',Location(inp))])
         self._test(inp,res)



    def testNonValid(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/nonvalid.xhtml"
        res = TestResults(
            [Observation('VA3',LineColumnLocation(inp,'utf-8',13,75),{'msg': u"Element 'area' not allowed here"}),
             Observation('VA3',LineColumnLocation(inp,'utf-8',13,75),{'msg': u"Element 'area' not declared"}),
             Observation("VA5",Location(inp))
             ])
        self._test(inp,res)

    def testBadEncoding(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/badencoding.xhtml?content-type=application/xhtml%2Bxml"
        res = TestResults(
            [Observation('VA2',LineColumnLocation(inp,'utf-8',1,0),{'msg': u"The encoding of the page is assumed to be UTF8, but it isn't. Make sure the proper encoding is declared in the Content-Type header or in the XML declaration"}),
             Observation('VA2',LineColumnLocation(inp,'utf-8',1,0),{'msg': 'Premature document end, no root element'}),
             Observation("VA4",Location(inp))
             ])
        self._test(inp,res)


def _test():
    unittest.main()

if __name__ == '__main__':
    _test()



