#!/usr/bin/python
"""
$Id: contentformat.py,v 1.9 2007/04/26 08:05:54 dom Exp $

The ContentFormatTestCase implements the validator.testcase.TestCase
interface for the tests related to the following BP:
*  Send content in a format that is known to be supported by the device.


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

# small class to encapsulate data about a DTD
class DTD:
    def __init__(self,name,idtype,id):
        self.name=name
        self.idtype=idtype
        self.id=id

# Tests regarding the CONTENT_FORMAT_SUPPORT and CONTENT_FORMAT_PREFERRED BP
class ContentFormatTestCase(testcase.LinksBasedTestCase):
    BpId = ["CONTENT_FORMAT_SUPPORT","CONTENT_FORMAT_PREFERRED"]

    def _getDoctype(self):
        import re
        if not self._content:
            return None
        # copied and adapted from
        # http://dev.w3.org/cvsweb/~checkout~/validator/httpd/cgi-bin/check?rev=1.458&content-type=text/plain
        doctype_regexp=re.compile("^(?:<\?xml[^\?]*\?>|)\s*<!DOCTYPE\s+(\w+)\s+(PUBLIC|SYSTEM)\s+(?:[\'\"])([^\"\']+)(?:[\"\'])[^>]*>",re.UNICODE | re.S | re.M)
        match = doctype_regexp.search(self._content)
        if match and len(match.groups())==3:
            g = match.groups()
            return DTD(g[0],g[1],g[2])
        else:
            return None

    def _observeLinks(self):
        from validator import utils
        from cgi import parse_header
        mime = None
        if self._headers and self._headers.has_key("content-type"):
            mime = parse_header(self._headers["content-type"])[0]
        # @@@ this should be loaded from the DDC profile
        # and passed as param?
        if not mime in ["application/xhtml+xml"]:
            if not mime in ["text/html","application/vnd.wap.xhtml+xml"]:
                self.addObservation(testcase.Observation("CF1",testcase.HeaderLocation(self.uri,"Content-Type"),{"mime":mime}))
            else:
                self.addObservation(testcase.Observation("CF7",testcase.HeaderLocation(self.uri,"Content-Type"),{"mime":mime}))

        #  check whether we have an accepted doctype
        dtd = doctype = self._getDoctype()
        if dtd:
            # @@@ this should be loaded from the DDC profile
            if (dtd.idtype=="PUBLIC" and not dtd.id in ["-//W3C//DTD XHTML Basic 1.0//EN"]) or (dtd.idtype=="SYSTEM" and not dtd.id in ["http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd"]):
                self.addObservation(testcase.Observation("CF4",testcase.Location(self.uri),{"dtd":dtd.id}))
        else:
            self.addObservation(testcase.Observation("CF5",testcase.Location(self.uri)))
        links = self.getLinks()
        for link in links:
            if link.nature==utils.LINK_TYPE_EMBED:
                # @@@ this should be loaded from the DDC profile
                # and passed as param?
                if not link.mime in ["image/jpeg","image/gif","text/css"]:
                    self.addObservation(testcase.Observation("CF1",link.location,{"mime":link.mime}))
                elif link.mime in ["image/jpeg","image/gif"]:
                    import Image, cStringIO
                    headers,content = self._http_request(link.target)
                    try:
                        image = Image.open(cStringIO.StringIO(content))
                        image.verify()
                    except Exception,msg:
                        self.addObservation(testcase.Observation("CF6",link.location,{"mime":link.mime,"error":str(msg),"image":link.target}))

        if not "CF1" in self._observations and not "CF4" in self._observations and not "CF5" in self._observations and not "CF6" in self._observations:
            self.addObservation(testcase.Observation("CF3",Location(self.uri)))
# -------------------------
# Unit tests for this module
import unittest

from validator.testcase import TestResults, Observation, Location, HeaderLocation, LineColumnLocation
class Tests(unittest.TestCase):
    def _test(self,inp,res):
        a = ContentFormatTestCase()
        self.assertEqual(a.run(inp),res)
    
    def testGoodFormats(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-1.xhtml?content-type=application/xhtml%2Bxml"
        res = TestResults(
            [Observation("CF3",Location(inp))]
            )
        self._test(inp,res)

    def testBadFormats(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-2.xhtml?content-type=text/html"
        res = TestResults(
            [Observation('CF7',HeaderLocation(inp,"Content-Type"),{'mime': 'text/html'}),
             Observation('CF1',LineColumnLocation(inp,'utf-8',11,30),{'mime': 'image/png'}),
             Observation('CF1',LineColumnLocation(inp,'utf-8',12,25),{'mime': 'image/svg+xml'})]
            )
        self._test(inp,res)
        
    def testInvalidImages(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-5.xhtml?content-type=application/xhtml%2Bxml"
        res = TestResults(
            [Observation('CF6',LineColumnLocation(inp,'utf-8',11,58),{'image': u'http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-5.xhtml?content-type=image%2Fgif', 'mime': 'image/gif', 'error': 'cannot identify image file'}),
             Observation('CF6',LineColumnLocation(inp,'utf-8',12,73),{'image': u'http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-5.xhtml?content-type=image%2Fgif', 'mime': 'image/gif', 'error': '@@@'}),
             Observation('CF6',LineColumnLocation(inp,'utf-8',13,59),{'image': u'http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-5.xhtml?content-type=image%2Fjpeg', 'mime': 'image/jpeg', 'error': 'cannot identify image file'})]
            )
        self._test(inp,res)
        

    def testNoDoctype(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-3.xhtml?content-type=application/xhtml%2Bxml" 
        res = TestResults(
            [Observation('CF5',Location(inp))]
            )
        self._test(inp,res)

    def testBadDoctype(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/contentformat-4.xhtml?content-type=application/xhtml%2Bxml" 
        res = TestResults(
            [Observation('CF4',Location(inp),{'dtd': '-//W3C//DTD XHTML Transitional 1.0//EN'})]
            )
        self._test(inp,res)

    
def _test():
    unittest.main()

if __name__ == '__main__':
    _test()



