Skip to content
Permalink
Browse files

[IMP] base: clean up image tools tests

Since all the tools have been merged into one, the tests can be restructured and
the duplicate tests removed.

PR: #31811
  • Loading branch information...
seb-odoo committed Mar 22, 2019
1 parent 0074c40 commit 1028034743fd0060a7a0388c233438aba9c0176b
Showing with 91 additions and 159 deletions.
  1. +91 −159 odoo/addons/base/tests/test_image.py
@@ -20,121 +20,77 @@ class TestImage(TransactionCase):
"""
def setUp(self):
super(TestImage, self).setUp()
# This is the base64 of a 1px * 1px image saved as PNG.
self.base64_image_1x1 = b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGNgYGAAAAAEAAH2FzhVAAAAAElFTkSuQmCC'
self.base64_1x1_png = b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGNgYGAAAAAEAAH2FzhVAAAAAElFTkSuQmCC'
self.base64_svg = base64.b64encode(b'<svg></svg>')
self.base64_image_1920_1080 = tools.image_to_base64(PIL.Image.new('RGB', (1920, 1080)), 'JPEG')
self.base64_1920x1080_jpeg = tools.image_to_base64(PIL.Image.new('RGB', (1920, 1080)), 'JPEG')

def test_00_base64_to_image(self):
"""Test that base64 is correctly opened as a PIL image."""
image = tools.base64_to_image(self.base64_1x1_png)
self.assertEqual(type(image), PIL.PngImagePlugin.PngImageFile, "base64 as bytes, correct format")
self.assertEqual(image.size, (1, 1), "base64 as bytes, correct size")

# CASE: base64 as bytes
image = tools.base64_to_image(self.base64_image_1x1)
self.assertEqual(type(image), PIL.PngImagePlugin.PngImageFile)
self.assertEqual(image.size, (1, 1))
image = tools.base64_to_image(self.base64_1x1_png.decode('ASCII'))
self.assertEqual(type(image), PIL.PngImagePlugin.PngImageFile, "base64 as string, correct format")
self.assertEqual(image.size, (1, 1), "base64 as string, correct size")

# CASE: base64 as string
image = tools.base64_to_image(self.base64_image_1x1.decode('ASCII'))
self.assertEqual(type(image), PIL.PngImagePlugin.PngImageFile)
self.assertEqual(image.size, (1, 1))

# CASE: wrong base64: binascii.Error: Incorrect padding
with self.assertRaises(binascii.Error):
with self.assertRaises(binascii.Error, msg="wrong base64: binascii.Error: Incorrect padding"):
image = tools.base64_to_image(b'oazdazpodazdpok')

# CASE: wrong base64: OSError: cannot identify image file
with self.assertRaises(OSError):
with self.assertRaises(OSError, msg="wrong base64: OSError: cannot identify image file"):
image = tools.base64_to_image(b'oazdazpodazdpokd')

def test_01_image_to_base64(self):
"""Test that a PIL image is correctly saved as base64."""
image = PIL.Image.new('RGB', (1, 1))
image_base64 = tools.image_to_base64(image, 'PNG')
self.assertEqual(image_base64, self.base64_image_1x1)

def test_10_image_process_resize(self):
"""Test that image_process is working as expected for resizeing."""

# CASE: return False if base64_source is falsy
res = tools.image_process(False)
self.assertFalse(res)

# CASE: return base64_source if format is SVG
res = tools.image_process(self.base64_svg)
self.assertEqual(res, self.base64_svg)

# CASE: correct resize (keep ratio)
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(800, 600)))
self.assertEqual(image.size, (800, 450))

# CASE: change format to PNG
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, format='PNG'))
self.assertEqual(image.format, 'PNG')

# CASE: change format to JPEG (case insensitive)
image = tools.base64_to_image(tools.image_process(self.base64_image_1x1, format='jpeg'))
self.assertEqual(image.format, 'JPEG')

# CASE: change format to BMP converted to PNG
image = tools.base64_to_image(tools.image_process(self.base64_image_1x1, format='BMP'))
self.assertEqual(image.format, 'PNG')

# CASE: change format PNG with RGBA to JPEG
base64_image_1080_1920_rgba = tools.image_to_base64(PIL.Image.new('RGBA', (1080, 1920)), 'PNG')
image = tools.base64_to_image(tools.image_process(base64_image_1080_1920_rgba, format='jpeg'))
self.assertEqual(image.format, 'JPEG')

# CASE: keep ratio if no height given
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(192, None)))
self.assertEqual(image.size, (192, 108))
self.assertEqual(image_base64, self.base64_1x1_png)

# CASE: keep ratio if no width given
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(None, 108)))
self.assertEqual(image.size, (192, 108))
def test_10_image_process_base64_source(self):
"""Test the base64_source parameter of image_process."""
self.assertFalse(tools.image_process(False), "return False if base64_source is falsy")
self.assertEqual(tools.image_process(self.base64_svg), self.base64_svg, "return base64_source if format is SVG")
self.assertFalse(tools.image_process(b'oazdazpodazdpok'), "return False if base64 is wrong")
self.assertFalse(tools.image_process(b'oazdazpodazdpokd'), "return False if image can't be identified")
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg))
self.assertEqual(image.size, (1920, 1080), "OK return the image")

# CASE: size above, return original
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(3000, 2000)))
self.assertEqual(image.size, (1920, 1080))
def test_11_image_process_size(self):
"""Test the size parameter of image_process."""

# CASE: same size, no change
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(1920, 1080)))
self.assertEqual(image.size, (1920, 1080))

# CASE: no resize if above
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(3000, None)))
self.assertEqual(image.size, (1920, 1080))

# CASE: no resize if above
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(None, 2000)))
self.assertEqual(image.size, (1920, 1080))

# CASE: vertical image, correct resize if below
base64_image_1080_1920 = tools.image_to_base64(PIL.Image.new('RGB', (1080, 1920)), 'PNG')
image = tools.base64_to_image(tools.image_process(base64_image_1080_1920, size=(3000, 192)))
self.assertEqual(image.size, (108, 192))

# CASE: adapt to width
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(192, 200)))
self.assertEqual(image.size, (192, 108))

# CASE: adapt to height
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(400, 108)))
self.assertEqual(image.size, (192, 108))

def test_11_image_process(self):
"""Test that image_proces is working as expected."""
# CASE: return base64_source if format is SVG
res = tools.image_process(self.base64_svg)
self.assertEqual(res, self.base64_svg)

# CASE: size excessive
# Format of `tests`: (original base64 image, size parameter, expected result, text)
tests = [
(self.base64_1920x1080_jpeg, (192, 108), (192, 108), "resize to given size"),
(self.base64_1920x1080_jpeg, (1920, 1080), (1920, 1080), "same size, no change"),
(self.base64_1920x1080_jpeg, (192, None), (192, 108), "set height from ratio"),
(self.base64_1920x1080_jpeg, (0, 108), (192, 108), "set width from ratio"),
(self.base64_1920x1080_jpeg, (192, 200), (192, 108), "adapt to width"),
(self.base64_1920x1080_jpeg, (400, 108), (192, 108), "adapt to height"),
(self.base64_1920x1080_jpeg, (3000, 2000), (1920, 1080), "don't resize above original, both set"),
(self.base64_1920x1080_jpeg, (3000, False), (1920, 1080), "don't resize above original, width set"),
(self.base64_1920x1080_jpeg, (None, 2000), (1920, 1080), "don't resize above original, height set"),
(base64_image_1080_1920, (3000, 192), (108, 192), "vertical image, resize if below"),
]

count = 10
for test in tests:
image = tools.base64_to_image(tools.image_process(test[0], size=test[1]))
self.assertEqual(image.size, test[2], test[3])
count = count - 1
self.assertEqual(count, 0, "ensure the loop is ran")

def test_12_image_process_verify_resolution(self):
"""Test the verify_resolution parameter of image_process."""
res = tools.image_process(self.base64_1920x1080_jpeg, verify_resolution=True)
self.assertNotEqual(res, False, "size ok")
base64_image_excessive = tools.image_to_base64(PIL.Image.new('RGB', (45001, 1000)), 'PNG')
with self.assertRaises(ValueError):
res = tools.image_process(base64_image_excessive, verify_resolution=True)
with self.assertRaises(ValueError, msg="size excessive"):
tools.image_process(base64_image_excessive, verify_resolution=True)

# CASE: max_width
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, (192, 0)))
self.assertEqual(image.size, (192, 108))
def test_13_image_process_quality(self):
"""Test the quality parameter of image_process."""

# CASE: PNG RGBA doesn't apply quality, just optimize
base64_image_1080_1920_rgba = tools.image_to_base64(PIL.Image.new('RGBA', (1080, 1920)), 'PNG')
@@ -146,100 +102,76 @@ def test_11_image_process(self):
res = tools.image_process(base64_image_1080_1920_rgb)
self.assertLessEqual(len(res), len(base64_image_1080_1920_rgb))

# CASE: JPEG strictly reduced quality
res = tools.image_process(self.base64_image_1920_1080)
self.assertLessEqual(len(res), len(self.base64_image_1920_1080))
# CASE: JPEG optimize + reduced quality
res = tools.image_process(self.base64_1920x1080_jpeg)
self.assertLessEqual(len(res), len(self.base64_1920x1080_jpeg))

# CASE: GIF doesn't apply quality, just optimize
base64_image_1080_1920_gif = tools.image_to_base64(PIL.Image.new('RGB', (1080, 1920)), 'GIF')
res = tools.image_process(base64_image_1080_1920_gif)
self.assertLessEqual(len(res), len(base64_image_1080_1920_gif))

# CASE: unsupported format
base64_image_1080_1920_tiff = tools.image_to_base64(PIL.Image.new('RGB', (1080, 1920)), 'TIFF')
image = tools.base64_to_image(tools.image_process(base64_image_1080_1920_tiff))
self.assertEqual(image.format, 'JPEG')

def test_12_image_process(self):
"""Test that image_process is working as expected with crop."""

# CASE: return False if base64_source is falsy
res = tools.image_process(False, size=(1, 1), crop='center')
self.assertFalse(res)
def test_14_image_process_crop(self):
"""Test the crop parameter of image_process."""

# CASE: size, crop biggest possible
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(2000, 2000), crop='center'))
self.assertEqual(image.size, (1080, 1080))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(2000, 2000), crop='center'))
self.assertEqual(image.size, (1080, 1080), "crop biggest possible")

# CASE: size vertical, limit height
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(2000, 4000), crop='center'))
self.assertEqual(image.size, (540, 1080))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(2000, 4000), crop='center'))
self.assertEqual(image.size, (540, 1080), "size vertical, limit height")

# CASE: size horizontal, limit width
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(4000, 2000), crop='center'))
self.assertEqual(image.size, (1920, 960))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(4000, 2000), crop='center'))
self.assertEqual(image.size, (1920, 960), "size horizontal, limit width")

# CASE: type center
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(2000, 2000), crop='center'))
self.assertEqual(image.size, (1080, 1080))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(512, 512), crop='center'))
self.assertEqual(image.size, (512, 512), "type center")

# CASE: type center
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(2000, 2000), crop='top'))
self.assertEqual(image.size, (1080, 1080))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(512, 512), crop='top'))
self.assertEqual(image.size, (512, 512), "type center")

# CASE: type bottom
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(2000, 2000), crop='bottom'))
self.assertEqual(image.size, (1080, 1080))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(512, 512), crop='bottom'))
self.assertEqual(image.size, (512, 512), "type bottom")

# CASE: wrong crop value, use center
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(2000, 2000), crop='wrong'))
self.assertEqual(image.size, (1080, 1080))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(512, 512), crop='wrong'))
self.assertEqual(image.size, (512, 512), "wrong crop value, use center")

# CASE: size given, resize too
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, size=(512, 512), crop='center'))
self.assertEqual(image.size, (512, 512))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, size=(192, 0), crop='center'))
self.assertEqual(image.size, (192, 108), "not cropped, just do resize")

def test_13_image_process_colorize(self):
"""Test that image_process is working as expected for colorize."""
def test_15_image_process_colorize(self):
"""Test the colorize parameter of image_process."""

# verify initial condition
image_rgba = PIL.Image.new('RGBA', (1, 1))
self.assertEqual(image_rgba.mode, 'RGBA')
self.assertEqual(image_rgba.getpixel((0, 0)), (0, 0, 0, 0))
base64_rgba = tools.image_to_base64(image_rgba, 'PNG')

# CASE: color random, color has changed
image = tools.base64_to_image(tools.image_process(base64_rgba, colorize=True))
self.assertEqual(image.mode, 'P')
self.assertNotEqual(image.getpixel((0, 0)), (0, 0, 0))

def test_14_image_get_format(self):
"""Test that image_get_format is working as expected."""
self.assertEqual(tools.image_get_format(self.base64_image_1x1), 'PNG')
self.assertEqual(tools.image_get_format(self.base64_svg), 'SVG')
self.assertEqual(tools.image_get_format(self.base64_image_1920_1080), 'JPEG')
def test_16_image_process_format(self):
"""Test the format parameter of image_process."""

def test_16_image_process_resize(self):
"""Test that image_process is working as expected."""
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, format='PNG'))
self.assertEqual(image.format, 'PNG', "change format to PNG")

# CASE: return input if no width or height
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080))
self.assertEqual(image.size, (1920, 1080))
image = tools.base64_to_image(tools.image_process(self.base64_1x1_png, format='JpEg'))
self.assertEqual(image.format, 'JPEG', "change format to JPEG (case insensitive)")

# CASE: given width, resize and keep ratio
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, (192, 0)))
self.assertEqual(image.size, (192, 108))
image = tools.base64_to_image(tools.image_process(self.base64_1920x1080_jpeg, format='BMP'))
self.assertEqual(image.format, 'PNG', "change format to BMP converted to PNG")

# CASE: given height, resize and keep ratio
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, (0, 108)))
self.assertEqual(image.size, (192, 108))

# CASE: crop
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, (192, 108), crop=True))
self.assertEqual(image.size, (192, 108))
base64_image_1080_1920_rgba = tools.image_to_base64(PIL.Image.new('RGBA', (108, 192)), 'PNG')
image = tools.base64_to_image(tools.image_process(base64_image_1080_1920_rgba, format='jpeg'))
self.assertEqual(image.format, 'JPEG', "change format PNG with RGBA to JPEG")

# CASE: keep ratio
image = tools.base64_to_image(tools.image_process(self.base64_image_1920_1080, (1000, 1000)))
self.assertEqual(image.size, (1000, 562))
base64_image_1080_1920_tiff = tools.image_to_base64(PIL.Image.new('RGB', (108, 192)), 'TIFF')
image = tools.base64_to_image(tools.image_process(base64_image_1080_1920_tiff))
self.assertEqual(image.format, 'JPEG', "unsupported format to JPEG")

def test_17_image_data_uri(self):
def test_20_image_data_uri(self):
"""Test that image_data_uri is working as expected."""
self.assertEqual(tools.image_data_uri(self.base64_image_1x1), 'data:image/png;base64,' + self.base64_image_1x1.decode('ascii'))
self.assertEqual(tools.image_data_uri(self.base64_1x1_png), 'data:image/png;base64,' + self.base64_1x1_png.decode('ascii'))

0 comments on commit 1028034

Please sign in to comment.
You can’t perform that action at this time.