#!/usr/bin/python
"""
$Id: images.py,v 1.12 2007/04/26 07:22:01 dom Exp $

The ObjectScriptTestCase implements the validator.testcase.TestCase
interface for the tests related to the following BPs:
* Specify the size of images in markup, if they have an intrinsic size.
* Resize images at the server, if they have an intrinsic size.
* Do not use graphics for spacing.

It relies on the Python Imaging Library (debian: python-imaging)
http://www.pythonware.com/products/pil/

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 

# Tests regarding the IMAGES_SPECIFY_SIZE, GRAPHICS_FOR_SPACING and IMAGES_RESIZING BP
class ImagesTestCase(testcase.LinksBasedTestCase):
    BpId = ["IMAGES_SPECIFY_SIZE", "GRAPHICS_FOR_SPACING", "IMAGES_RESIZING"]
    
    def startDocument(self):
        self._imagesList = {}
        testcase.LinksBasedTestCase.startDocument(self)

        
    def startElement(self,name,attrs):
        # checking whether the width and height were given in the markup
        if name=="img" and attrs.has_key("src"):
            location = testcase.LineColumnLocation(self.uri,self.getEncoding(),self.locator.getLineNumber(),self.locator.getColumnNumber())
            target = self._absolutize(attrs['src'])
            if not self._imagesList.has_key(target):
                self._imagesList[target] = []
            dims = {"location":location}
            
            if attrs.has_key("width"):
                if not "%" in attrs["width"]:
                    try:
                        dims["width"] = int(attrs["width"])
                    except ValueError:
                        self.addObservation(Observation("LE1",location,{"attribute":"width","value":attrs["width"],"expected":"a number or percents"}))
                else:
                    self.addObservation(testcase.Observation("IG7",location))
            else:
                self.addObservation(testcase.Observation("IG1",location))
            if attrs.has_key("height"):
                if not "%" in attrs["height"]:
                    try:
                        dims["height"] = int(attrs["height"])
                    except ValueError:
                        self.addObservation(Observation("LE1",location,{"attribute":"length","value":attrs["height"],"expected":"a number or percents"}))
                else:
                    self.addObservation(testcase.Observation("IG8",location))
            else:
                self.addObservation(testcase.Observation("IG2",location))
            self._imagesList[target].append(dims)
        testcase.LinksBasedTestCase.startElement(self,name,attrs)


    def _observeLinks(self):
        if not "IG1" in self._observations and not "IG2" in self._observations and not "IG7"  in self._observations and not "IG8"  in self._observations:
            self.addObservation(testcase.Observation("IG5",testcase.Location(self.uri)))
        import validator.utils
        import Image, cStringIO
        links = self.getLinks()
        for link in links:
            if link.mime and link.mime.split("/")[0]=='image':
                headers,content = self._http_request(link.target)
                # loading the image from the HTTP request
                try:
                    image = Image.open(cStringIO.StringIO(content))
                except IOError("cannot identify image file"):
                    self.addObservation(testcase.Observation("IG7",link.location))
                width,height = image.size
                # very small graphic; suspect a breech of GRAPHICS_FOR_SPACING
                if width<=2 and height<=2:
                    smallGraphics = True
                else:
                    smallGraphics = False
                # detecting fully transparent images
                # @@@ this only deals with GIF I suppose
                transparentImage = False
                if image.info.has_key("transparency"):
                    trans_pix = image.info["transparency"]
                    histogram = image.histogram()
                    # is there any non-transparent pixel?
                    f = filter(lambda x:x[1] and x[0]!=trans_pix,enumerate(histogram))
                    if not len(f):
                        transparentImage = True
                if self._imagesList.has_key(link.target):
                    for i in self._imagesList[link.target]:
                        if i['location']==link.location:
                            if i.has_key("width") and i["width"]!=width:
                                self.addObservation(testcase.Observation("IG3",i['location'],{"intrinsic":width,"markup":i["width"]}))
                            if i.has_key("height") and i["height"]!=height:
                                self.addObservation(testcase.Observation("IG4",i['location'],{"intrinsic":height,"markup":i["height"]}))
                            if smallGraphics:
                                self.addObservation(testcase.Observation("IG9",i['location']))
                            if transparentImage:
                                self.addObservation(testcase.Observation("IG10",i['location']))
                        
        if not "IG3" in self._observations and not "IG4" in self._observations and "IG5"  in self._observations:
            self.addObservation(testcase.Observation("IG6",testcase.Location(self.uri)))        
                

# -------------------------
# 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 = ImagesTestCase()
        self.assertEqual(a.run(inp),res)

    def testWithImagesRight(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/images-1.xhtml"
        res = TestResults(
            [Observation("IG5",Location(inp)),
             Observation("IG6",Location(inp))]
            )
        self._test(inp,res)

    def testWithImagesNoDim(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/images-2.xhtml"
        res = TestResults(
            [Observation('IG1',LineColumnLocation(inp,'utf-8',13,3)),
             Observation('IG2',LineColumnLocation(inp,'utf-8',13,3))]
            )
        self._test(inp,res)

    def testWithImagesNotMatching(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/images-3.xhtml"
        res = TestResults(
            [Observation('IG5',Location(inp)),
             Observation('IG3',LineColumnLocation(inp,'utf-8',13,3),{"markup":36,"intrinsic":72}),
             Observation('IG4',LineColumnLocation(inp,'utf-8',13,3),{"markup":24,"intrinsic":48})]
            )
        self._test(inp,res)

    def testWithImagePercent(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/images-4.xhtml"
        res = TestResults(
            [Observation('IG7',LineColumnLocation(inp,'utf-8',13,3)),
             Observation('IG8',LineColumnLocation(inp,'utf-8',13,3))]
            )
        self._test(inp,res)

    def testWithSpacerImage(self):
        inp = "http://dev.w3.org/cvsweb/~checkout~/2006/mwbp-validator/tests/graphics_spacing.xhtml"
        res = TestResults(
            [Observation("IG5",Location(inp)),
             Observation('IG9',LineColumnLocation(inp,'utf-8',11,24)),
             Observation('IG10',LineColumnLocation(inp,'utf-8',11,24)),
             Observation("IG6",Location(inp))
             ]
            )
        self._test(inp,res)



def _test():
    unittest.main()

if __name__ == '__main__':
    _test()



