Exemple #1
0
class TestCloudinaryImage(unittest.TestCase):
  def setUp(self):
    cloudinary.config(cloud_name="test", api_secret="1234")
    self.image = CloudinaryImage("hello", format = "png")

  def test_build_url(self):
    """should generate url """
    self.assertEqual(self.image.build_url(), "http://res.cloudinary.com/test/image/upload/hello.png")

  def test_url(self):
    """should url property """
    self.assertEqual(self.image.url, "http://res.cloudinary.com/test/image/upload/hello.png")

  def test_image(self):
    """should generate image """
    self.assertEqual(self.image.image(), "<img src='http://res.cloudinary.com/test/image/upload/hello.png' />")

  def test_image_unicode(self):
    """should generate image with unicode arguments """
    self.assertEqual(self.image.image(alt=u"\ua000abcd\u07b4"), u"<img src='http://res.cloudinary.com/test/image/upload/hello.png' alt='\ua000abcd\u07b4'/>")

  def test_scale(self):
    """should accept scale crop and pass width/height to image tag """
    self.assertEqual(self.image.image(crop='scale', width=100, height=100), "<img src='http://res.cloudinary.com/test/image/upload/c_scale,h_100,w_100/hello.png' height='100' width='100'/>")

  def test_validate(self):
    """should validate signature """
    self.assertFalse(self.image.validate())
    self.assertFalse(CloudinaryImage("hello", format = "png", version="1234", signature="1234").validate())
    self.assertTrue(CloudinaryImage("hello", format = "png", version="1234", signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate())
Exemple #2
0
class TestCloudinaryImage(unittest.TestCase):
    def setUp(self):
        cloudinary.config(cloud_name="test", api_secret="1234")
        self.image = CloudinaryImage("hello", format = "png")

    def test_build_url(self):
        """should generate url """
        self.assertEqual(self.image.build_url(), "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_url(self):
        """should url property """
        self.assertEqual(self.image.url, "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_image(self):
        """should generate image """
        self.assertEqual(self.image.image(), "<img src='http://res.cloudinary.com/test/image/upload/hello.png' />")

    def test_image_unicode(self):
        """should generate image with unicode arguments """
        self.assertEqual(self.image.image(alt=u"\ua000abcd\u07b4"), u"<img src='http://res.cloudinary.com/test/image/upload/hello.png' alt='\ua000abcd\u07b4'/>")

    def test_scale(self):
        """should accept scale crop and pass width/height to image tag """
        self.assertEqual(self.image.image(crop='scale', width=100, height=100), "<img src='http://res.cloudinary.com/test/image/upload/c_scale,h_100,w_100/hello.png' height='100' width='100'/>")

    def test_validate(self):
        """should validate signature """
        self.assertFalse(self.image.validate())
        self.assertFalse(CloudinaryImage("hello", format = "png", version="1234", signature="1234").validate())
        self.assertTrue(CloudinaryImage("hello", format = "png", version="1234", signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate())
Exemple #3
0
class ImageTest(unittest.TestCase):
    def setUp(self):
        cloudinary.config(cloud_name="test", api_secret="1234")
        self.image = CloudinaryImage("hello", format = "png")

    def test_build_url(self):
        """should generate url """
        self.assertEqual(self.image.build_url(), "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_url(self):
        """should url property """
        self.assertEqual(self.image.url, "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_image(self):
        """should generate image """
        self.assertEqual(self.image.image(), "<img src='http://res.cloudinary.com/test/image/upload/hello.png'/>")

    def test_image_unicode(self):
        """should generate image with unicode arguments """
        self.assertEqual(self.image.image(alt=u"\ua000abcd\u07b4"), u"<img src='http://res.cloudinary.com/test/image/upload/hello.png' alt='\ua000abcd\u07b4'/>")

    def test_scale(self):
        """should accept scale crop and pass width/height to image tag """
        self.assertEqual(self.image.image(crop='scale', width=100, height=100), "<img src='http://res.cloudinary.com/test/image/upload/c_scale,h_100,w_100/hello.png' height='100' width='100'/>")

    def test_validate(self):
        """should validate signature """
        self.assertFalse(self.image.validate())
        self.assertFalse(CloudinaryImage("hello", format = "png", version="1234", signature="1234").validate())
        self.assertTrue(CloudinaryImage("hello", format = "png", version="1234", signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate())

    def test_responsive_width(self):
        """should add responsive width transformation"""
        self.assertEqual(self.image.image(responsive_width = True), "<img class='cld-responsive' data-src='http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png'/>")

    def test_width_auto(self):
        """should support width=auto """
        self.assertEqual(self.image.image(width = "auto", crop = "limit"), "<img class='cld-responsive' data-src='http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png'/>")

    def test_dpr_auto(self):
        """should support dpr=auto """
        self.assertEqual(self.image.image(dpr = "auto"), "<img class='cld-hidpi' data-src='http://res.cloudinary.com/test/image/upload/dpr_auto/hello.png'/>")
Exemple #4
0
    def to_python(self, value):
        """Convert to CloudinaryImage"""
        if not value:
            return None

        m = cloudinary.utils.API_URL_REGEX.search(value)
        if m:
            if m.group('resource_type') != 'image':
                raise forms.ValidationError("Only images are supported")
            image = CloudinaryImage(m.group('public_id'), format=m.group('image_format'), version=m.group('version'),
                                    signature=m.group('signature'), type=m.group('image_type'))
            if not image.validate():
                raise forms.ValidationError("Signature mistmatch")
            return image

        m = cloudinary.utils.PUBLIC_ID_REGEX.search(value)
        if m:
            return CloudinaryImage(m.group('public_id'), format=m.group('format'), version=m.group('version'))

        raise forms.ValidationError("Invalid format")
Exemple #5
0
class ImageTest(unittest.TestCase):
    def setUp(self):
        cloudinary.config(cloud_name="test", api_secret="1234")
        self.image = CloudinaryImage("hello", format="png")

    def test_build_url(self):
        """should generate url """
        self.assertEqual(
            self.image.build_url(),
            "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_url(self):
        """should url property """
        self.assertEqual(
            self.image.url,
            "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_image(self):
        """should generate image """
        self.assertEqual(
            self.image.image(),
            "<img src=\"http://res.cloudinary.com/test/image/upload/hello.png\"/>"
        )

    def test_image_unicode(self):
        """should generate image with unicode arguments """
        self.assertEqual(
            self.image.image(alt=u"\ua000abcd\u07b4"),
            u"<img alt=\"\ua000abcd\u07b4\" src=\"http://res.cloudinary.com/test/image/upload/hello.png\"/>"
        )

    def test_scale(self):
        """should accept scale crop and pass width/height to image tag """
        self.assertEqual(
            self.image.image(crop="scale", width=100, height=100),
            "<img height=\"100\" src=\"http://res.cloudinary.com/test/image/upload/c_scale,h_100,w_100/hello.png\" width=\"100\"/>"
        )

    def test_validate(self):
        """should validate signature """
        self.assertFalse(self.image.validate())
        self.assertFalse(
            CloudinaryImage("hello",
                            format="png",
                            version="1234",
                            signature="1234").validate())
        self.assertTrue(
            CloudinaryImage(
                "hello",
                format="png",
                version="1234",
                signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate(
                ))

    def test_responsive_width(self):
        """should add responsive width transformation"""
        self.assertEqual(
            self.image.image(responsive_width=True),
            "<img class=\"cld-responsive\" data-src=\"http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png\"/>"
        )

    def test_width_auto(self):
        """should support width=auto """
        self.assertEqual(
            self.image.image(width="auto", crop="limit"),
            "<img class=\"cld-responsive\" data-src=\"http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png\"/>"
        )

    def test_dpr_auto(self):
        """should support dpr=auto """
        self.assertEqual(
            self.image.image(dpr="auto"),
            "<img class=\"cld-hidpi\" data-src=\"http://res.cloudinary.com/test/image/upload/dpr_auto/hello.png\"/>"
        )
Exemple #6
0
class ImageTest(unittest.TestCase):
    def setUp(self):
        cloudinary.reset_config()
        cloudinary.config(cloud_name="test", api_secret="1234")
        self.image = CloudinaryImage("hello", format="png")

    def test_build_url(self):
        """should generate url """
        self.assertEqual(
            self.image.build_url(),
            'http://res.cloudinary.com/test/image/upload/hello.png')

    def test_url(self):
        """should url property """
        self.assertEqual(
            self.image.url,
            'http://res.cloudinary.com/test/image/upload/hello.png')

    def test_image(self):
        """should generate image """
        self.assertEqual(
            self.image.image(),
            '<img src="http://res.cloudinary.com/test/image/upload/hello.png"/>'
        )

    def test_image_unicode(self):
        """should generate image with unicode arguments """
        self.assertEqual(
            self.image.image(alt=u"\ua000abcd\u07b4"),
            u'<img alt="\ua000abcd\u07b4" src="http://res.cloudinary.com/test/image/upload/hello.png"/>'
        )

    def test_scale(self):
        """should accept scale crop and pass width/height to image tag """
        self.assertEqual(
            self.image.image(crop="scale", width=100, height=100),
            '<img height="100" src="http://res.cloudinary.com/test/image/upload/c_scale,h_100,w_100/hello.png" width="100"/>'
        )

    def test_validate(self):
        """should validate signature """
        self.assertFalse(self.image.validate())
        self.assertFalse(
            CloudinaryImage("hello",
                            format="png",
                            version="1234",
                            signature="1234").validate())
        self.assertTrue(
            CloudinaryImage(
                "hello",
                format="png",
                version="1234",
                signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate(
                ))

    def test_responsive_width(self):
        """should add responsive width transformation"""
        self.assertEqual(
            self.image.image(responsive_width=True),
            '<img class="cld-responsive" data-src="http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png"/>'
        )

    def test_width_auto(self):
        """should support width=auto """
        self.assertEqual(
            self.image.image(width="auto", crop="limit"),
            '<img class="cld-responsive" data-src="http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png"/>'
        )

    def test_dpr_auto(self):
        """should support dpr=auto """
        self.assertEqual(
            self.image.image(dpr="auto"),
            '<img class="cld-hidpi" data-src="http://res.cloudinary.com/test/image/upload/dpr_auto/hello.png"/>'
        )

    def shared_client_hints(self, **options):
        """should not use data-src or set responsive class"""
        tag = CloudinaryImage('sample.jpg').image(**options)
        six.assertRegex(self, tag, '<img.*>',
                        "should not use data-src or set responsive class")
        self.assertIsNone(re.match('<.* class.*>', tag),
                          "should not use data-src or set responsive class")
        self.assertIsNone(re.match('\bdata-src\b', tag),
                          "should not use data-src or set responsive class")
        six.assertRegex(
            self, tag,
            'src=["\']http://res.cloudinary.com/test/image/upload/c_scale,dpr_auto,w_auto/sample.jpg["\']',
            "should not use data-src or set responsive class")
        cloudinary.config(responsive=True)
        tag = CloudinaryImage('sample.jpg').image(**options)
        six.assertRegex(self, tag, '<img.*>')
        self.assertIsNone(re.match('<.* class.*>', tag),
                          "should override responsive")
        self.assertIsNone(re.match('\bdata-src\b', tag),
                          "should override responsive")
        six.assertRegex(
            self, tag,
            'src=["\']http://res.cloudinary.com/test/image/upload/c_scale,dpr_auto,w_auto/sample.jpg["\']',
            "should override responsive")

    def test_client_hints_as_options(self):
        self.shared_client_hints(dpr="auto",
                                 cloud_name="test",
                                 width="auto",
                                 crop="scale",
                                 client_hints=True)

    def test_client_hints_as_global(self):
        cloudinary.config(client_hints=True)
        self.shared_client_hints(dpr="auto",
                                 cloud_name="test",
                                 width="auto",
                                 crop="scale")

    def test_client_hints_as_false(self):
        """should use normal responsive behaviour"""
        cloudinary.config(responsive=True)
        tag = CloudinaryImage('sample.jpg').image(width="auto",
                                                  crop="scale",
                                                  cloud_name="test",
                                                  client_hints=False)
        six.assertRegex(self, tag, '<img.*>')
        six.assertRegex(self, tag, 'class=["\']cld-responsive["\']')
        six.assertRegex(
            self, tag,
            'data-src=["\']http://res.cloudinary.com/test/image/upload/c_scale,w_auto/sample.jpg["\']'
        )

    def test_width_auto_breakpoints(self):
        """supports auto width"""
        tag = CloudinaryImage('sample.jpg')\
            .image(crop="scale", dpr="auto", cloud_name="test", width="auto:breakpoints", client_hints=True)
        six.assertRegex(
            self, tag,
            'src=["\']http://res.cloudinary.com/test/image/upload/c_scale,dpr_auto,w_auto:breakpoints/sample.jpg["\']'
        )
Exemple #7
0
class ImageTest(unittest.TestCase):
    def setUp(self):
        self.cloud_name = 'test123'
        self.public_id = "sample"
        self.image_format = "jpg"
        self.full_public_id = "{id}.{format}".format(id=self.public_id,
                                                     format=self.image_format)
        self.upload_url = "http://res.cloudinary.com/{cloud_name}/image/upload".format(
            cloud_name=self.cloud_name)
        self.common_format = {
            "url": self.upload_url,
            "id": self.full_public_id
        }
        self.image = CloudinaryImage(self.public_id, format=self.image_format)

        self.common_image_options = {
            "effect": "sepia",
            "cloud_name": self.cloud_name
        }
        self.common_transformation_str = 'e_sepia'
        self.breakpoint_list = [100, 200, 300, 399]
        self.common_srcset = {"breakpoints": self.breakpoint_list}
        self.custom_attributes = {
            'custom_attr1': 'custom_value1',
            'custom_attr2': 'custom_value2'
        }

        cloudinary.reset_config()
        cloudinary.config(cloud_name=self.cloud_name,
                          api_secret="1234",
                          cname=None)

    def test_build_url(self):
        """should generate url """
        self.assertEqual(self.image.build_url(),
                         '{url}/{id}'.format(**self.common_format))

    def test_url(self):
        """should url property """
        self.assertEqual(self.image.url,
                         '{url}/{id}'.format(**self.common_format))

    def test_image(self):
        """should generate image """
        self.assertEqual(
            self.image.image(),
            '<img src="{url}/{id}"/>'.format(**self.common_format))

    def test_image_unicode(self):
        """should generate image with unicode arguments """
        self.assertEqual(
            self.image.image(alt=u"\ua000abcd\u07b4"),
            u'<img alt="\ua000abcd\u07b4" src="{url}/{id}"/>'.format(
                **self.common_format))

    def test_scale(self):
        """should accept scale crop and pass width/height to image tag """
        self.assertEqual(
            self.image.image(crop="scale", width=100, height=100),
            '<img height="100" src="{url}/c_scale,h_100,w_100/{id}" width="100"/>'
            .format(**self.common_format))

    def test_validate(self):
        """should validate signature """
        self.assertFalse(self.image.validate())
        self.assertFalse(
            CloudinaryImage("hello",
                            format="png",
                            version="1234",
                            signature="1234").validate())
        self.assertTrue(
            CloudinaryImage(
                "hello",
                format="png",
                version="1234",
                signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate(
                ))

    def test_responsive_width(self):
        """should add responsive width transformation"""
        self.assertEqual(
            self.image.image(responsive_width=True),
            '<img class="cld-responsive" data-src="{url}/c_limit,w_auto/{id}"/>'
            .format(**self.common_format))

    def test_width_auto(self):
        """should support width=auto """
        self.assertEqual(
            self.image.image(width="auto", crop="limit"),
            '<img class="cld-responsive" data-src="{url}/c_limit,w_auto/{id}"/>'
            .format(**self.common_format))

    def test_dpr_auto(self):
        """should support dpr=auto """
        self.assertEqual(
            self.image.image(dpr="auto"),
            '<img class="cld-hidpi" data-src="{url}/dpr_auto/{id}"/>'.format(
                **self.common_format))

    def test_effect_art_incognito(self):
        """should support effect art:incognito """
        e = "art:incognito"
        self.assertEqual(
            self.image.image(effect=e),
            '<img src="{url}/e_{e}/{id}"/>'.format(e=e, **self.common_format))

    def shared_client_hints(self, **options):
        """should not use data-src or set responsive class"""
        tag = CloudinaryImage(self.full_public_id).image(**options)
        six.assertRegex(self, tag, '<img.*>',
                        "should not use data-src or set responsive class")
        self.assertIsNone(re.match('<.* class.*>', tag),
                          "should not use data-src or set responsive class")
        self.assertIsNone(re.match('\bdata-src\b', tag),
                          "should not use data-src or set responsive class")
        expected_re = 'src=["\']{url}/c_scale,dpr_auto,w_auto/{id}["\']'.format(
            **self.common_format)
        six.assertRegex(self, tag, expected_re,
                        "should not use data-src or set responsive class")
        cloudinary.config(responsive=True)
        tag = CloudinaryImage(self.full_public_id).image(**options)
        six.assertRegex(self, tag, '<img.*>')
        self.assertIsNone(re.match('<.* class.*>', tag),
                          "should override responsive")
        self.assertIsNone(re.match('\bdata-src\b', tag),
                          "should override responsive")

        six.assertRegex(self, tag, expected_re, "should override responsive")

    def test_client_hints_as_options(self):
        self.shared_client_hints(dpr="auto",
                                 cloud_name=self.cloud_name,
                                 width="auto",
                                 crop="scale",
                                 client_hints=True)

    def test_client_hints_as_global(self):
        cloudinary.config(client_hints=True)
        self.shared_client_hints(dpr="auto",
                                 cloud_name=self.cloud_name,
                                 width="auto",
                                 crop="scale")

    def test_client_hints_as_false(self):
        """should use normal responsive behaviour"""
        cloudinary.config(responsive=True)
        tag = CloudinaryImage(self.full_public_id).image(
            width="auto",
            crop="scale",
            cloud_name=self.cloud_name,
            client_hints=False)
        six.assertRegex(self, tag, '<img.*>')
        six.assertRegex(self, tag, 'class=["\']cld-responsive["\']')
        exp = 'data-src=["\']{url}/c_scale,w_auto/{id}["\']'.format(
            **self.common_format)
        six.assertRegex(self, tag, exp)

    def test_width_auto_breakpoints(self):
        """supports auto width"""
        tag = CloudinaryImage(self.full_public_id).image(
            crop="scale",
            dpr="auto",
            cloud_name=self.cloud_name,
            width="auto:breakpoints",
            client_hints=True)
        expected_re = 'src=["\']{url}/c_scale,dpr_auto,w_auto:breakpoints/{id}["\']'.format(
            **self.common_format)
        six.assertRegex(self, tag, expected_re)

    def _get_expected_cl_image_tag(self,
                                   public_id,
                                   common_trans_str,
                                   custom_trans_str=None,
                                   srcset_breakpoints=None,
                                   attributes=None):
        """
        Helper method for generating expected image tag

        :param public_id:           Public ID of the image
        :param common_trans_str:    Default transformation string to be used in all resources
        :param custom_trans_str:    Optional custom transformation string to be be used inside srcset resources.
                                    If not provided, common_trans_str is used
        :param srcset_breakpoints:  Optional list of breakpoints for srcset. If not provided srcset is omitted
        :param attributes:          Optional dict of custom attributes to be added to the tag

        :return: Resulting image tag
        """
        if not custom_trans_str:
            custom_trans_str = common_trans_str

        if attributes is None:
            attributes = dict()

        if srcset_breakpoints:
            bp_template = "{upload_url}/{custom_trans_str}/c_scale,w_{{w}}/{public_id} {{w}}w".format(
                upload_url=self.upload_url,
                custom_trans_str=custom_trans_str,
                public_id=public_id)
            attributes['srcset'] = ', '.join(
                bp_template.format(w=bp) for bp in srcset_breakpoints)

        attributes[
            "src"] = "{upload_url}/{common_trans_str}/{public_id}".format(
                upload_url=self.upload_url,
                common_trans_str=common_trans_str,
                public_id=public_id)

        attributes_str = " ".join(
            '{k}="{v}"'.format(k=k, v=attributes[k])
            for k in sorted(attributes)) if attributes else ""

        tag = "<img"

        if attributes_str:
            tag += " " + attributes_str

        tag += "/>"
        return tag

    def test_srcset_from_breakpoints(self):
        """Should create srcset attribute with provided breakpoints"""
        tag = CloudinaryImage(self.full_public_id).image(
            srcset=self.common_srcset, **self.common_image_options)
        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_from_float_breakpoints(self):
        """Should create srcset attribute with provided breakpoints as float values"""
        float_breakpoint_list = [bp + 0.1 for bp in self.breakpoint_list]
        self.common_srcset = {"breakpoints": float_breakpoint_list}
        tag = CloudinaryImage(self.full_public_id).image(
            srcset=self.common_srcset, **self.common_image_options)
        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            srcset_breakpoints=float_breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_from_min_width_max_width_max_images(self):
        """Should support srcset attribute defined by min_width, max_width, and max_images"""
        srcset_params = {
            "min_width": self.breakpoint_list[0],
            "max_width": self.breakpoint_list[-1],
            "max_images": len(self.breakpoint_list)
        }

        tag = CloudinaryImage(self.full_public_id).image(
            srcset=srcset_params, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_with_one_image(self):
        """Should support 1 image in srcset"""
        srcset_params = {
            "min_width": self.breakpoint_list[0],
            "max_width": self.breakpoint_list[-1],
            "max_images": 1
        }

        tag_by_params = CloudinaryImage(self.full_public_id).image(
            srcset=srcset_params, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            srcset_breakpoints=[self.breakpoint_list[-1]])
        self.assertEqual(expected_tag, tag_by_params)

        srcset_breakpoint = {"breakpoints": [self.breakpoint_list[-1]]}
        tag_by_breakpoint = CloudinaryImage(self.full_public_id).image(
            srcset=srcset_breakpoint, **self.common_image_options)
        self.assertEqual(expected_tag, tag_by_breakpoint)

    def test_srcset_with_custom_transformation(self):
        """Should support custom transformation for srcset items"""
        srcset_params = copy.deepcopy(self.common_srcset)
        srcset_params["transformation"] = {
            "crop": "crop",
            "width": 10,
            "height": 20
        }
        custom_transformation_str = "c_crop,h_20,w_10"

        tag = CloudinaryImage(self.full_public_id).image(
            srcset=srcset_params, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            custom_trans_str=custom_transformation_str,
            srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_with_sizes_attribute(self):
        """Should populate sizes attribute"""
        srcset_params = copy.deepcopy(self.common_srcset)
        srcset_params["sizes"] = True
        tag = CloudinaryImage(self.full_public_id).image(
            srcset=srcset_params, **self.common_image_options)

        expected_sizes_attr = ", ".join("(max-width: {w}px) {w}px".format(w=bp)
                                        for bp in self.breakpoint_list)
        attributes = {"sizes": expected_sizes_attr}
        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            srcset_breakpoints=self.breakpoint_list,
            attributes=attributes)
        self.assertEqual(expected_tag, tag)

    def test_srcset_from_string(self):
        """Should support srcset string value"""
        raw_srcset_value = "some srcset data as is"
        tag = CloudinaryImage(self.full_public_id).image(
            srcset=raw_srcset_value, **self.common_image_options)

        attributes = {"srcset": raw_srcset_value}
        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            attributes=attributes)
        self.assertEqual(expected_tag, tag)

    def test_srcset_width_height_removed(self):
        """Should remove width and height attributes in case srcset is specified, but passed to transformation"""
        tag = CloudinaryImage(self.full_public_id).image(
            width=500,
            height=500,
            srcset=self.common_srcset,
            **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str + ",h_500,w_500",
            srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_invalid_values(self):
        """Should raise ValueError on invalid values"""
        invalid_srcset_params = [
            {
                'sizes': True
            },  # srcset data not provided
            {
                'max_width': 300,
                'max_images': 3
            },  # no min_width
            {
                'min_width': '1',
                'max_width': 300,
                'max_images': 3
            },  # invalid min_width
            {
                'min_width': 100,
                'max_images': 3
            },  # no max_width
            {
                'min_width': 100,
                'max_width': '3',
                'max_images': 3
            },  # invalid max_width
            {
                'min_width': 200,
                'max_width': 100,
                'max_images': 3
            },  # min_width > max_width
            {
                'min_width': 100,
                'max_width': 300
            },  # no max_images
            {
                'min_width': 100,
                'max_width': 300,
                'max_images': 0
            },  # invalid max_images
            {
                'min_width': 100,
                'max_width': 300,
                'max_images': -17
            },  # invalid max_images
            {
                'min_width': 100,
                'max_width': 300,
                'max_images': '3'
            },  # invalid max_images
        ]

        for invalid_srcset in invalid_srcset_params:
            with self.assertRaises(ValueError):
                CloudinaryImage(self.full_public_id).image(
                    srcset=invalid_srcset, **self.common_image_options)

    def test_custom_attributes(self):
        """ Should consume custom attributes from 'attributes' key"""
        tag = CloudinaryImage(self.full_public_id).image(
            attributes=self.custom_attributes, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            attributes=self.custom_attributes)
        self.assertEqual(expected_tag, tag)

    def test_custom_attributes_legacy(self):
        """ Should consume custom attributes as is from options"""
        custom_options = copy.deepcopy(self.common_image_options)
        custom_options.update(self.custom_attributes)
        tag = CloudinaryImage(self.full_public_id).image(**custom_options)

        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            attributes=self.custom_attributes)
        self.assertEqual(expected_tag, tag)

    def test_custom_attributes_override_existing(self):
        """ Attributes from 'attributes' dict should override existing attributes"""
        updated_attributes = {"alt": "updated alt"}
        tag = CloudinaryImage(self.full_public_id).image(
            alt="original alt",
            attributes=updated_attributes,
            **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.common_transformation_str,
            attributes=updated_attributes)
        self.assertEqual(expected_tag, tag)
Exemple #8
0
class ImageTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.logger = cloudinary.logger

        if os.getenv("DEBUG"):
            cls.logger.setLevel(logging.DEBUG)

    def setUp(self):
        self.cloud_name = 'test123'
        self.public_id = "sample"
        self.image_format = "jpg"
        self.full_public_id = "{id}.{format}".format(id=self.public_id, format=self.image_format)
        self.upload_url = "http://res.cloudinary.com/{cloud_name}/image/upload".format(cloud_name=self.cloud_name)
        self.common_format = {"url": self.upload_url, "id": self.full_public_id}
        self.image = CloudinaryImage(self.public_id, format=self.image_format)

        self.common_transformation = {"effect": "sepia"}
        self.common_transformation_str = 'e_sepia'
        self.common_image_options = {"cloud_name": self.cloud_name}
        self.common_image_options.update(self.common_transformation)
        self.custom_attributes = {'custom_attr1': 'custom_value1', 'custom_attr2': 'custom_value2'}

        self.min_width = 100
        self.max_width = 399
        self.breakpoint_list = [self.min_width, 200, 300, self.max_width]
        self.common_srcset = {"breakpoints": self.breakpoint_list}

        self.fill_transformation = {"width": self.max_width, "height": self.max_width, "crop": "fill"}
        self.fill_transformation_str = "c_fill,h_{h},w_{w}".format(h=self.max_width, w=self.max_width)

        cloudinary.reset_config()
        cloudinary.config(cloud_name=self.cloud_name, api_secret="1234", cname=None)

    def test_build_url(self):
        """should generate url """
        self.assertEqual(self.image.build_url(), '{url}/{id}'.format(**self.common_format))

    def test_url(self):
        """should url property """
        self.assertEqual(self.image.url, '{url}/{id}'.format(**self.common_format))

    def test_image(self):
        """should generate image """
        self.assertEqual(self.image.image(), '<img src="{url}/{id}"/>'.format(**self.common_format))

    def test_image_unicode(self):
        """should generate image with unicode arguments """
        self.assertEqual(
            self.image.image(alt=u"\ua000abcd\u07b4"),
            u'<img alt="\ua000abcd\u07b4" src="{url}/{id}"/>'.format(**self.common_format))

    def test_scale(self):
        """should accept scale crop and pass width/height to image tag """
        self.assertEqual(
            self.image.image(crop="scale", width=100, height=100),
            '<img height="100" src="{url}/c_scale,h_100,w_100/{id}" width="100"/>'.format(**self.common_format))

    def test_validate(self):
        """should validate signature """
        self.assertFalse(self.image.validate())
        self.assertFalse(CloudinaryImage("hello", format="png", version="1234", signature="1234").validate())
        self.assertTrue(CloudinaryImage("hello", format="png", version="1234",
                                        signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate())

    def test_responsive_width(self):
        """should add responsive width transformation"""
        self.assertEqual(self.image.image(responsive_width=True),
                         '<img class="cld-responsive" data-src="{url}/c_limit,w_auto/{id}"/>'.format(
                             **self.common_format))

    def test_width_auto(self):
        """should support width=auto """
        self.assertEqual(self.image.image(width="auto", crop="limit"),
                         '<img class="cld-responsive" data-src="{url}/c_limit,w_auto/{id}"/>'.format(
                             **self.common_format))

    def test_dpr_auto(self):
        """should support dpr=auto """
        self.assertEqual(self.image.image(dpr="auto"),
                         '<img class="cld-hidpi" data-src="{url}/dpr_auto/{id}"/>'.format(**self.common_format))

    def test_effect_art_incognito(self):
        """should support effect art:incognito """
        e = "art:incognito"
        self.assertEqual(self.image.image(effect=e), '<img src="{url}/e_{e}/{id}"/>'.format(e=e, **self.common_format))

    def shared_client_hints(self, **options):
        """should not use data-src or set responsive class"""
        tag = CloudinaryImage(self.full_public_id).image(**options)
        six.assertRegex(self, tag, '<img.*>', "should not use data-src or set responsive class")
        self.assertIsNone(re.match('<.* class.*>', tag), "should not use data-src or set responsive class")
        self.assertIsNone(re.match('\bdata-src\b', tag), "should not use data-src or set responsive class")
        expected_re = 'src=["\']{url}/c_scale,dpr_auto,w_auto/{id}["\']'.format(**self.common_format)
        six.assertRegex(self, tag, expected_re, "should not use data-src or set responsive class")
        cloudinary.config(responsive=True)
        tag = CloudinaryImage(self.full_public_id).image(**options)
        six.assertRegex(self, tag, '<img.*>')
        self.assertIsNone(re.match('<.* class.*>', tag), "should override responsive")
        self.assertIsNone(re.match('\bdata-src\b', tag), "should override responsive")

        six.assertRegex(self, tag, expected_re, "should override responsive")

    def test_client_hints_as_options(self):
        self.shared_client_hints(dpr="auto", cloud_name=self.cloud_name, width="auto", crop="scale", client_hints=True)

    def test_client_hints_as_global(self):
        cloudinary.config(client_hints=True)
        self.shared_client_hints(dpr="auto", cloud_name=self.cloud_name, width="auto", crop="scale")

    def test_client_hints_as_false(self):
        """should use normal responsive behaviour"""
        cloudinary.config(responsive=True)
        tag = CloudinaryImage(self.full_public_id).image(width="auto", crop="scale", cloud_name=self.cloud_name,
                                                         client_hints=False)
        six.assertRegex(self, tag, '<img.*>')
        six.assertRegex(self, tag, 'class=["\']cld-responsive["\']')
        exp = 'data-src=["\']{url}/c_scale,w_auto/{id}["\']'.format(**self.common_format)
        six.assertRegex(self, tag, exp)

    def test_width_auto_breakpoints(self):
        """supports auto width"""
        tag = CloudinaryImage(self.full_public_id).image(crop="scale", dpr="auto", cloud_name=self.cloud_name,
                                                         width="auto:breakpoints", client_hints=True)
        expected_re = 'src=["\']{url}/c_scale,dpr_auto,w_auto:breakpoints/{id}["\']'.format(**self.common_format)
        six.assertRegex(self, tag, expected_re)

    def _common_image_tag_helper(self, tag_name, public_id, common_trans_str, custom_trans_str=None,
                                srcset_breakpoints=None, attributes=None, is_void=False):
        """
        Helper method for generating expected img and source tags

        :param tag_name:            Expected tag name(img or source)
        :param public_id:           Public ID of the image
        :param common_trans_str:    Default transformation string to be used in all resources
        :param custom_trans_str:    Optional custom transformation string to be be used inside srcset resources.
                                    If not provided, common_trans_str is used
        :param srcset_breakpoints:  Optional list of breakpoints for srcset. If not provided srcset is omitted
        :param attributes:          Optional dict of custom attributes to be added to the tag
        :param is_void:             Indicates whether tag is an HTML5 void tag (does not need to be self-closed)

        :return: Resulting tag
        """
        if not custom_trans_str:
            custom_trans_str = common_trans_str

        if attributes is None:
            attributes = dict()

        if srcset_breakpoints:
            bp_template = "{upload_url}{custom_trans_str}/c_scale,w_{{w}}/{public_id} {{w}}w".format(
                upload_url=self.upload_url,
                custom_trans_str="/" + custom_trans_str if custom_trans_str else "",
                public_id=public_id)
            attributes['srcset'] = ', '.join(bp_template.format(w=bp) for bp in srcset_breakpoints)

        attributes_str = " ".join(
            '{k}="{v}"'.format(k=k, v=attributes[k]) for k in sorted(attributes)) if attributes else ""

        tag = "<{}".format(tag_name)

        if attributes_str:
            tag += " " + attributes_str

        tag += "/>" if not is_void else ">"  # HTML5 void elements do not need to be self closed

        self.logger.debug(re.sub(r'([,"]) ', r'\1\n    ', tag))

        return tag

    def _get_expected_cl_image_tag(self, public_id, common_trans_str, custom_trans_str=None, srcset_breakpoints=None,
                                   attributes=None):
        """
        Helper method for generating expected image tag

        :param public_id:           Public ID of the image
        :param common_trans_str:    Default transformation string to be used in all resources
        :param custom_trans_str:    Optional custom transformation string to be be used inside srcset resources.
                                    If not provided, common_trans_str is used
        :param srcset_breakpoints:  Optional list of breakpoints for srcset. If not provided srcset is omitted
        :param attributes:          Optional dict of custom attributes to be added to the tag

        :return: Resulting image tag
        """

        if attributes is None:
            attributes = OrderedDict()

        attributes["src"] = "{upload_url}{common_trans_str}/{public_id}".format(
            upload_url=self.upload_url,
            common_trans_str="/" + common_trans_str if common_trans_str else "",
            public_id=public_id)

        return self._common_image_tag_helper("img", public_id, common_trans_str, custom_trans_str, srcset_breakpoints,
                                             attributes)

    @staticmethod
    def _get_expected_media_attr(**media_options):
        media_query_conditions = []
        if "min_width" in media_options:
            media_query_conditions.append("(min-width: {}px)".format(media_options["min_width"]))
        if "max_width" in media_options:
            media_query_conditions.append("(max-width: {}px)".format(media_options["max_width"]))

        return " and ".join(media_query_conditions)

    def _get_expected_cl_source_tag(self, public_id, common_trans_str, custom_trans_str=None, srcset_breakpoints=None,
                                    media=None, attributes=None):
        """
        Helper method for generating expected image tag

        :param public_id:           Public ID of the image
        :param common_trans_str:    Default transformation string to be used in all resources
        :param custom_trans_str:    Optional custom transformation string to be be used inside srcset resources.
                                    If not provided, common_trans_str is used
        :param srcset_breakpoints:  Optional list of breakpoints for srcset. If not provided srcset is omitted
        :param attributes:          Optional dict of custom attributes to be added to the tag

        :return: Resulting image tag
        """

        if attributes is None:
            attributes = OrderedDict()

        if media:
            attributes["media"] = self._get_expected_media_attr(**media)

        attributes["srcset"] = "{upload_url}{common_trans_str}/{public_id}".format(
            upload_url=self.upload_url,
            common_trans_str="/" + common_trans_str if common_trans_str else "",
            public_id=public_id)

        return self._common_image_tag_helper("source", public_id, common_trans_str, custom_trans_str,
                                             srcset_breakpoints, attributes, True)

    def test_srcset_from_breakpoints(self):
        """Should create srcset attribute with provided breakpoints"""
        tag = CloudinaryImage(self.full_public_id).image(srcset=self.common_srcset, **self.common_image_options)
        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_from_float_breakpoints(self):
        """Should create srcset attribute with provided breakpoints as float values"""
        float_breakpoint_list = [bp + 0.1 for bp in self.breakpoint_list]
        self.common_srcset = {"breakpoints": float_breakpoint_list}
        tag = CloudinaryImage(self.full_public_id).image(srcset=self.common_srcset, **self.common_image_options)
        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       srcset_breakpoints=float_breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_from_min_width_max_width_max_images(self):
        """Should support srcset attribute defined by min_width, max_width, and max_images"""
        srcset_params = {"min_width": self.min_width, "max_width": self.max_width,
                         "max_images": len(self.breakpoint_list)}

        tag = CloudinaryImage(self.full_public_id).image(srcset=srcset_params, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_with_one_image(self):
        """Should support 1 image in srcset"""
        srcset_params = {"min_width": self.min_width, "max_width": self.max_width,
                         "max_images": 1}

        tag_by_params = CloudinaryImage(self.full_public_id).image(srcset=srcset_params, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       srcset_breakpoints=[self.max_width])
        self.assertEqual(expected_tag, tag_by_params)

        srcset_breakpoint = {"breakpoints": [self.max_width]}
        tag_by_breakpoint = CloudinaryImage(self.full_public_id).image(srcset=srcset_breakpoint,
                                                                       **self.common_image_options)
        self.assertEqual(expected_tag, tag_by_breakpoint)

    def test_srcset_with_custom_transformation(self):
        """Should support custom transformation for srcset items"""
        srcset_params = copy.deepcopy(self.common_srcset)
        srcset_params["transformation"] = {"crop": "crop", "width": 10, "height": 20}
        custom_transformation_str = "c_crop,h_20,w_10"

        tag = CloudinaryImage(self.full_public_id).image(srcset=srcset_params, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       custom_trans_str=custom_transformation_str,
                                                       srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_with_sizes_attribute(self):
        """Should populate sizes attribute"""
        srcset_params = copy.deepcopy(self.common_srcset)
        srcset_params["sizes"] = True
        tag = CloudinaryImage(self.full_public_id).image(srcset=srcset_params, **self.common_image_options)

        expected_sizes_attr = ", ".join("(max-width: {w}px) {w}px".format(w=bp) for bp in self.breakpoint_list)
        attributes = {"sizes": expected_sizes_attr}
        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       srcset_breakpoints=self.breakpoint_list, attributes=attributes)
        self.assertEqual(expected_tag, tag)

    def test_srcset_from_string(self):
        """Should support srcset string value"""
        raw_srcset_value = "some srcset data as is"
        attributes = {"srcset": raw_srcset_value}

        tag = CloudinaryImage(self.full_public_id).image(attributes=attributes, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       attributes=attributes)
        self.assertEqual(expected_tag, tag)

        legacy_tag = CloudinaryImage(self.full_public_id).image(srcset=raw_srcset_value, **self.common_image_options)
        self.assertEqual(expected_tag, legacy_tag)

    def test_srcset_width_height_removed(self):
        """Should remove width and height attributes in case srcset is specified, but passed to transformation"""
        tag = CloudinaryImage(self.full_public_id).image(width=500, height=500, srcset=self.common_srcset,
                                                         **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id,
                                                       self.common_transformation_str + ",h_500,w_500",
                                                       srcset_breakpoints=self.breakpoint_list)
        self.assertEqual(expected_tag, tag)

    def test_srcset_invalid_values(self):
        """Should raise ValueError on invalid values"""
        invalid_srcset_params = [
            {'sizes': True},                                          # srcset data not provided
            {'max_width': 300, 'max_images': 3},                      # no min_width
            {'min_width': '1', 'max_width': 300, 'max_images': 3},    # invalid min_width
            {'min_width': 100, 'max_images': 3},                      # no max_width
            {'min_width': 100, 'max_width': '3', 'max_images': 3},    # invalid max_width
            {'min_width': 200, 'max_width': 100, 'max_images': 3},    # min_width > max_width
            {'min_width': 100, 'max_width': 300},                     # no max_images
            {'min_width': 100, 'max_width': 300, 'max_images': 0},    # invalid max_images
            {'min_width': 100, 'max_width': 300, 'max_images': -17},  # invalid max_images
            {'min_width': 100, 'max_width': 300, 'max_images': '3'},  # invalid max_images
        ]
        with mock.patch('cloudinary.logger') as log_mock:
            for invalid_srcset in invalid_srcset_params:
                image_tag = CloudinaryImage(self.full_public_id).image(srcset=invalid_srcset,
                                                                       **self.common_image_options)
                self.assertNotIn("srcset", image_tag)

            expected_log_call_count = len(invalid_srcset_params) + 1  # When `sizes` is True we call log twice
            self.assertEqual(expected_log_call_count, log_mock.warning.call_count)

    def test_custom_attributes(self):
        """ Should consume custom attributes from 'attributes' key"""
        tag = CloudinaryImage(self.full_public_id).image(attributes=self.custom_attributes, **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       attributes=self.custom_attributes)
        self.assertEqual(expected_tag, tag)

    def test_custom_attributes_legacy(self):
        """ Should consume custom attributes as is from options"""
        custom_options = copy.deepcopy(self.common_image_options)
        custom_options.update(self.custom_attributes)
        tag = CloudinaryImage(self.full_public_id).image(**custom_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       attributes=self.custom_attributes)
        self.assertEqual(expected_tag, tag)

    def test_custom_attributes_override_existing(self):
        """ Attributes from 'attributes' dict should override existing attributes"""
        updated_attributes = {"alt": "updated alt"}
        tag = CloudinaryImage(self.full_public_id).image(alt="original alt", attributes=updated_attributes,
                                                         **self.common_image_options)

        expected_tag = self._get_expected_cl_image_tag(self.full_public_id, self.common_transformation_str,
                                                       attributes=updated_attributes)
        self.assertEqual(expected_tag, tag)

    def test_source_tag(self):
        """should generate source tag"""
        tag = CloudinaryImage(self.full_public_id).source(**self.common_image_options)
        expected_tag = self._get_expected_cl_source_tag(self.full_public_id, self.common_transformation_str)

        self.assertEqual(expected_tag, tag)

    def test_source_tag_media_query(self):
        """should generate source tag with media query"""
        media = {"min_width": self.min_width, "max_width": self.max_width}
        tag = CloudinaryImage(self.full_public_id).source(media=media)
        expected_media = "(min-width: {min}px) and (max-width: {max}px)".format(min=self.min_width,
                                                                                     max=self.max_width)
        expected_tag = self._get_expected_cl_source_tag(self.full_public_id, "", attributes={"media": expected_media})

        self.assertEqual(expected_tag, tag)

    def test_source_tag_responsive_srcset(self):
        """should generate source tag with responsive srcset"""
        tag = CloudinaryImage(self.full_public_id).source(srcset=self.common_srcset)
        expected_tag = self._get_expected_cl_source_tag(self.full_public_id, "",
                                                        srcset_breakpoints=self.breakpoint_list)

        self.assertEqual(expected_tag, tag)

    def test_picture_tag(self):
        """should generate picture tag"""
        tag = CloudinaryImage(self.full_public_id).picture(sources=[
            {"max_width": self.min_width,
             "transformation": {"effect": "sepia", "angle": 17, "width": self.min_width}},
            {"min_width": self.min_width,
             "max_width": self.max_width,
             "transformation": {"effect": "colorize", "angle": 18, "width": self.max_width}},
            {"min_width": self.max_width,
             "transformation": {"effect": "blur", "angle": 19, "width": self.max_width}}
        ], **self.fill_transformation)

        expected_source_1 = self._get_expected_cl_source_tag(
            self.full_public_id,
            "{tr}/a_17,e_sepia,w_{w}".format(tr=self.fill_transformation_str, w=self.min_width),
            media={"max_width": self.min_width}
        )

        expected_source_2 = self._get_expected_cl_source_tag(
            self.full_public_id,
            "{tr}/a_18,e_colorize,w_{w}".format(tr=self.fill_transformation_str, w=self.max_width),
            media={"min_width": self.min_width, "max_width": self.max_width}
        )

        expected_source_3 = self._get_expected_cl_source_tag(
            self.full_public_id,
            "{tr}/a_19,e_blur,w_{w}".format(tr=self.fill_transformation_str, w=self.max_width),
            media={"min_width": self.max_width}
        )

        expected_img = self._get_expected_cl_image_tag(
            self.full_public_id,
            self.fill_transformation_str,
            attributes={"height": self.max_width, "width": self.max_width}
        )

        exp_tag = '<picture>' + expected_source_1 + expected_source_2 + expected_source_3 + expected_img + '</picture>'

        self.assertEqual(exp_tag, tag)
class ImageTest(unittest.TestCase):
    def setUp(self):
        cloudinary.reset_config()
        cloudinary.config(cloud_name="test", api_secret="1234")
        self.image = CloudinaryImage("hello", format = "png")

    def test_build_url(self):
        """should generate url """
        self.assertEqual(self.image.build_url(), "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_url(self):
        """should url property """
        self.assertEqual(self.image.url, "http://res.cloudinary.com/test/image/upload/hello.png")

    def test_image(self):
        """should generate image """
        self.assertEqual(self.image.image(), "<img src=\"http://res.cloudinary.com/test/image/upload/hello.png\"/>")

    def test_image_unicode(self):
        """should generate image with unicode arguments """
        self.assertEqual(self.image.image(alt=u"\ua000abcd\u07b4"), u"<img alt=\"\ua000abcd\u07b4\" src=\"http://res.cloudinary.com/test/image/upload/hello.png\"/>")

    def test_scale(self):
        """should accept scale crop and pass width/height to image tag """
        self.assertEqual(self.image.image(crop="scale", width=100, height=100), "<img height=\"100\" src=\"http://res.cloudinary.com/test/image/upload/c_scale,h_100,w_100/hello.png\" width=\"100\"/>")

    def test_validate(self):
        """should validate signature """
        self.assertFalse(self.image.validate())
        self.assertFalse(CloudinaryImage("hello", format = "png", version="1234", signature="1234").validate())
        self.assertTrue(CloudinaryImage("hello", format = "png", version="1234", signature="2aa73bf69fb50816e5509e32275b8c417dcb880d").validate())

    def test_responsive_width(self):
        """should add responsive width transformation"""
        self.assertEqual(self.image.image(responsive_width = True), "<img class=\"cld-responsive\" data-src=\"http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png\"/>")

    def test_width_auto(self):
        """should support width=auto """
        self.assertEqual(self.image.image(width = "auto", crop = "limit"), "<img class=\"cld-responsive\" data-src=\"http://res.cloudinary.com/test/image/upload/c_limit,w_auto/hello.png\"/>")

    def test_dpr_auto(self):
        """should support dpr=auto """
        self.assertEqual(self.image.image(dpr = "auto"), "<img class=\"cld-hidpi\" data-src=\"http://res.cloudinary.com/test/image/upload/dpr_auto/hello.png\"/>")
    
    
    def shared_client_hints(self, **options):
        """should not use data-src or set responsive class"""
        tag = CloudinaryImage('sample.jpg').image(**options)
        self.assertRegexpMatches(tag, '<img.*>', "should not use data-src or set responsive class" )
        self.assertNotRegexpMatches(tag, '<.* class.*>', "should not use data-src or set responsive class")
        self.assertNotRegexpMatches(tag, '\bdata-src\b', "should not use data-src or set responsive class" )
        self.assertRegexpMatches(tag, 'src=["\']http://res.cloudinary.com/test/image/upload/c_scale,dpr_auto,w_auto/sample.jpg["\']', "should not use data-src or set responsive class")
        cloudinary.config(responsive= True)
        tag = CloudinaryImage('sample.jpg').image(**options)
        self.assertRegexpMatches(tag, '<img.*>' )
        self.assertNotRegexpMatches(tag, '<.* class.*>', "should override responsive")
        self.assertNotRegexpMatches(tag, '\bdata-src\b', "should override responsive" )
        self.assertRegexpMatches(tag, 'src=["\']http://res.cloudinary.com/test/image/upload/c_scale,dpr_auto,w_auto/sample.jpg["\']', "should override responsive")
        
    def test_client_hints_as_options(self):
        self.shared_client_hints( dpr= "auto", cloud_name= "test", width= "auto", crop= "scale", client_hints= True)
    def test_client_hints_as_global(self):
        cloudinary.config(client_hints = True)
        self.shared_client_hints(dpr= "auto", cloud_name= "test", width= "auto", crop= "scale")

    def test_client_hints_as_false(self):
        """should use normal responsive behaviour"""
        cloudinary.config(responsive = True)
        tag = CloudinaryImage('sample.jpg').image(width= "auto", crop= "scale", cloud_name= "test", client_hints= False)
        self.assertRegexpMatches(tag, '<img.*>')
        self.assertRegexpMatches(tag, 'class=["\']cld-responsive["\']')
        self.assertRegexpMatches(tag, 'data-src=["\']http://res.cloudinary.com/test/image/upload/c_scale,w_auto/sample.jpg["\']')
    def test_width_auto_breakpoints(self):
        """supports auto width"""
        tag = CloudinaryImage( 'sample.jpg').image( crop= "scale", dpr= "auto", cloud_name= "test", width= "auto=breakpoints", client_hints= True)
        self.assertRegexpMatches(tag, 'src=["\']http://res.cloudinary.com/test/image/upload/c_scale,dpr_auto,w_auto=breakpoints/sample.jpg["\']')