Skip to content

Commit

Permalink
tests for OptionsNamer and process_image
Browse files Browse the repository at this point in the history
  • Loading branch information
fgmacedo committed Apr 15, 2016
1 parent e90cea2 commit e88c82f
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 16 deletions.
31 changes: 22 additions & 9 deletions filebrowser/namers.py
@@ -1,3 +1,4 @@
import re
from django.utils import six
from django.utils.module_loading import import_string

Expand Down Expand Up @@ -33,20 +34,33 @@ class OptionsNamer(VersionNamer):
def get_version_name(self):
name = "{root}_{options}{extension}".format(
root=self.file_object.filename_root,
options='--'.join(self.prepared_options),
options=self.options_as_string,
extension=self.file_object.extension,
)
return name

def get_original_name(self):
"Removes the substring containing the last _ (underscore) in the filename"
"""
Restores the original file name wipping out the last
`_version_suffix--plus-any-configs` block entirely.
"""
root = self.file_object.filename_root
tmp = root.split("_")
options_part = tmp[len(tmp) - 1]
return u"%s%s" % (root.replace("_%s" % options_part, ""), self.file_object.extension)

@property
def prepared_options(self):
def options_as_string(self):
"""
The options part should not contain `_` (underscore) on order to get
original name back.
"""
name = '--'.join(self.options_list).replace(',', 'x')
name = re.sub(r'[_\s]', '-', name)
return re.sub(r'[^\w-]', '', name).strip()

@property
def options_list(self):
opts = []
if not self.options:
return opts
Expand All @@ -56,8 +70,10 @@ def prepared_options(self):

if 'size' in self.options:
opts.append('%sx%s' % tuple(self.options['size']))
elif 'width' in self.options:
opts.append('%sx%s' % (self.options['width'], self.options['width'],))
elif 'width' in self.options or 'height' in self.options:
width = float(self.options.get('width') or 0)
height = float(self.options.get('height') or 0)
opts.append('%dx%d' % (width, height))

for k, v in sorted(self.options.items()):
if not v or k in ('size', 'width', 'height',
Expand All @@ -71,9 +87,6 @@ def prepared_options(self):
v = 'x'.join([six.text_type(v) for item in v])
except TypeError:
v = six.text_type(v)
opts.append('%s-%s' % (k, self.sanitize_value(v)))
opts.append('%s-%s' % (k, v))

return opts

def sanitize_value(self, value):
return value.replace(',', 'x')
7 changes: 5 additions & 2 deletions filebrowser/utils.py
Expand Up @@ -73,17 +73,20 @@ def process_image(source, processor_options, processors=None):
return image


def scale_and_crop(im, width, height, opts='', **kwargs):
def scale_and_crop(im, width=None, height=None, opts='', **kwargs):
"""
Scale and Crop.
"""
x, y = [float(v) for v in im.size]
width = float(width or 0)
height = float(height or 0)

if (x, y) == (width, height):
return im

if 'upscale' not in opts:
if (x < width or not width) and (y < height or not height):
return False
return im

if width:
xr = float(width)
Expand Down
80 changes: 80 additions & 0 deletions tests/test_base.py
Expand Up @@ -419,3 +419,83 @@ def test_walk(self):
self.assertEqual(list(f.path for f in self.F_LISTING_FOLDER.files_walk_filtered()), [u'_test/uploads/testimage.jpg', u'_test/uploads/folder', u'_test/uploads/folder/subfolder', u'_test/uploads/folder/subfolder/testimage.jpg'])
self.assertEqual(self.F_LISTING_FOLDER.results_walk_total(), 4)
self.assertEqual(self.F_LISTING_FOLDER.results_walk_filtered(), 4)


class FileObjecNamerTests(TestCase):

PATCH_VERSIONS = {
'thumbnail': {'verbose_name': 'Thumbnail (1 col)', 'width': 60, 'height': 60, 'opts': 'crop'},
'small': {'verbose_name': 'Small (2 col)', 'width': 140, 'height': '', 'opts': ''},
'large': {'verbose_name': 'Large (8 col)', 'width': 680, 'height': '', 'opts': ''},
}
PATCH_ADMIN_VERSIONS = ['large']

def setUp(self):
super(FileObjecNamerTests, self).setUp()
shutil.copy(self.STATIC_IMG_PATH, self.FOLDER_PATH)

@patch('filebrowser.namers.VERSION_NAMER', 'filebrowser.namers.OptionsNamer')
def test_init_attributes(self):
"""
FileObject init attributes
# path
# head
# filename
# filename_lower
# filename_root
# extension
# mimetype
"""
self.assertEqual(self.F_IMAGE.path, "_test/uploads/folder/testimage.jpg")
self.assertEqual(self.F_IMAGE.head, '_test/uploads/folder')
self.assertEqual(self.F_IMAGE.filename, 'testimage.jpg')
self.assertEqual(self.F_IMAGE.filename_lower, 'testimage.jpg')
self.assertEqual(self.F_IMAGE.filename_root, 'testimage')
self.assertEqual(self.F_IMAGE.extension, '.jpg')
self.assertEqual(self.F_IMAGE.mimetype, ('image/jpeg', None))

@patch('filebrowser.namers.VERSION_NAMER', 'filebrowser.namers.OptionsNamer')
@patch('filebrowser.base.VERSIONS', PATCH_VERSIONS)
@patch('filebrowser.base.ADMIN_VERSIONS', PATCH_ADMIN_VERSIONS)
def test_version_attributes_with_options_namer(self):
"""
FileObject version attributes/methods
without versions_basedir
# is_version
# original
# original_filename
# versions_basedir
# versions
# admin_versions
# version_name(suffix)
# version_path(suffix)
# version_generate(suffix)
"""
# new settings
version_list = sorted([
'_test/_versions/folder/testimage_large--680x0.jpg',
'_test/_versions/folder/testimage_small--140x0.jpg',
'_test/_versions/folder/testimage_thumbnail--60x60--opts-crop.jpg'
])
admin_version_list = ['_test/_versions/folder/testimage_large--680x0.jpg']

self.assertEqual(self.F_IMAGE.is_version, False)
self.assertEqual(self.F_IMAGE.original.path, self.F_IMAGE.path)
self.assertEqual(self.F_IMAGE.versions_basedir, "_test/_versions/")
self.assertEqual(self.F_IMAGE.versions(), version_list)
self.assertEqual(self.F_IMAGE.admin_versions(), admin_version_list)
self.assertEqual(self.F_IMAGE.version_name("large"), "testimage_large--680x0.jpg")
self.assertEqual(self.F_IMAGE.version_path("large"), "_test/_versions/folder/testimage_large--680x0.jpg")

# version does not exist yet
f_version = FileObject(os.path.join(site.directory, 'folder', "testimage_large--680x0.jpg"), site=site)
self.assertEqual(f_version.exists, False)
# generate version
f_version = self.F_IMAGE.version_generate("large")
self.assertEqual(f_version.path, "_test/_versions/folder/testimage_large--680x0.jpg")
self.assertEqual(f_version.exists, True)
self.assertEqual(f_version.is_version, True)
self.assertEqual(f_version.original_filename, "testimage.jpg")
self.assertEqual(f_version.original.path, self.F_IMAGE.path)
95 changes: 95 additions & 0 deletions tests/test_namers.py
@@ -0,0 +1,95 @@
# coding: utf-8

import shutil

from mock import patch

from filebrowser.settings import VERSIONS
from tests import FilebrowserTestCase as TestCase

from filebrowser.namers import OptionsNamer


class BaseNamerTests(TestCase):
NAMER_CLASS = OptionsNamer

def setUp(self):
super(BaseNamerTests, self).setUp()
shutil.copy(self.STATIC_IMG_PATH, self.FOLDER_PATH)

def _get_namer(self, version_suffix, file_object=None, **extra_options):
if not file_object:
file_object = self.F_IMAGE

extra_options.update(VERSIONS.get(version_suffix, {}))

return self.NAMER_CLASS(
file_object=file_object,
version_suffix=version_suffix,
filename_root=file_object.filename_root,
extension=file_object.extension,
options=extra_options,
)


class OptionsNamerTests(BaseNamerTests):

def test_should_return_correct_version_name_using_predefined_versions(self):
expected = [
("admin_thumbnail", "testimage_admin-thumbnail--60x60--opts-crop.jpg", ),
("thumbnail", "testimage_thumbnail--60x60--opts-crop.jpg", ),
("small", "testimage_small--140x0.jpg", ),
("medium", "testimage_medium--300x0.jpg", ),
("big", "testimage_big--460x0.jpg", ),
("large", "testimage_large--680x0.jpg", ),
]

for version_suffix, expected_name in expected:
namer = self._get_namer(version_suffix)
self.assertEqual(namer.get_version_name(), expected_name)

@patch('filebrowser.namers.VERSION_NAMER', 'filebrowser.namers.OptionsNamer')
def test_should_return_correct_original_name_using_predefined_versions(self):
expected = 'testimage.jpg'
for version_suffix in VERSIONS.keys():
file_object = self.F_IMAGE.version_generate(version_suffix)
namer = self._get_namer(version_suffix, file_object)
self.assertNotEqual(file_object.filename, expected)

self.assertEqual(namer.get_original_name(), expected)
self.assertEqual(file_object.original_filename, expected)

def test_should_append_extra_options(self):
expected = [
(
"thumbnail",
"testimage_thumbnail--60x60--opts-crop--sepia.jpg",
{'sepia': True}
), (
"small",
"testimage_small--140x0--thumb--transparency-08.jpg",
{'transparency': 0.8, 'thumb': True}
), (
"large",
"testimage_large--680x0--nested-xpto-ops--thumb.jpg",
{'thumb': True, 'nested': {'xpto': 'ops'}}
),
]

for version_suffix, expected_name, extra_options in expected:
namer = self._get_namer(version_suffix, **extra_options)
self.assertEqual(namer.get_version_name(), expected_name)

def test_generated_version_name_options_list_should_be_ordered(self):
"the order is important to always generate the same name"
expected = [
(
"small",
"testimage_small--140x0--a--x-crop--z-4.jpg",
{'z': 4, 'a': True, 'x': 'crop'}
),
]

for version_suffix, expected_name, extra_options in expected:
namer = self._get_namer(version_suffix, **extra_options)
self.assertEqual(namer.get_version_name(), expected_name)
65 changes: 60 additions & 5 deletions tests/test_versions.py
Expand Up @@ -8,7 +8,8 @@

from tests import FilebrowserTestCase as TestCase
from filebrowser.settings import STRICT_PIL
from filebrowser.utils import scale_and_crop
from filebrowser import utils
from filebrowser.utils import scale_and_crop, process_image

if STRICT_PIL:
from PIL import Image
Expand All @@ -19,13 +20,67 @@
import Image


def processor_mark_1(im, **kwargs):
im.mark_1 = True
return im


def processor_mark_2(im, **kwargs):
im.mark_2 = True
return im


class ImageProcessorsTests(TestCase):
def setUp(self):
super(ImageProcessorsTests, self).setUp()
shutil.copy(self.STATIC_IMG_PATH, self.FOLDER_PATH)

utils._default_processors = None
self.im = Image.open(self.F_IMAGE.path_full)

def tearDown(self):
super(ImageProcessorsTests, self).tearDown()
utils._default_processors = None

def test_process_image_calls_scale_and_crop(self):
version = process_image(self.im, {'width': 500, 'height': ""})
self.assertEqual(version.size, (500, 375))

@patch('filebrowser.utils.PROCESSORS', [
'tests.test_versions.processor_mark_1',
'tests.test_versions.processor_mark_2',
])
def test_process_image_calls_the_stack_of_processors_in_settings(self):
version = process_image(self.im, {})
self.assertTrue(hasattr(version, 'mark_1'))
self.assertTrue(hasattr(version, 'mark_2'))

@patch('filebrowser.utils.PROCESSORS', [
'tests.test_versions.processor_mark_1',
])
def test_process_image_calls_only_explicit_provided_processors(self):
version = process_image(self.im, {}, processors=[processor_mark_2])
self.assertFalse(hasattr(version, 'mark_1'))
self.assertTrue(hasattr(version, 'mark_2'))


class ScaleAndCropTests(TestCase):
def setUp(self):
super(ScaleAndCropTests, self).setUp()
shutil.copy(self.STATIC_IMG_PATH, self.FOLDER_PATH)

self.im = Image.open(self.F_IMAGE.path_full)

def test_do_not_scale(self):
version = scale_and_crop(self.im, "", "", "")
self.assertEqual(version.size, self.im.size)

def test_do_not_scale_if_desired_size_is_equal_to_original(self):
width, height = self.im.size
version = scale_and_crop(self.im, width, height, "")
self.assertIs(version, self.im)
self.assertEqual(version.size, (width, height))

def test_scale_width(self):
version = scale_and_crop(self.im, 500, "", "")
self.assertEqual(version.size, (500, 375))
Expand All @@ -37,15 +92,15 @@ def test_scale_height(self):

def test_scale_no_upscale_too_wide(self):
version = scale_and_crop(self.im, 1500, "", "")
self.assertEqual(version, False)
self.assertIs(version, self.im)

def test_scale_no_upscale_too_tall(self):
version = scale_and_crop(self.im, "", 1125, "")
self.assertEqual(version, False)
self.assertIs(version, self.im)

def test_scale_no_upscale_too_wide_and_tall(self):
version = scale_and_crop(self.im, 1500, 1125, "")
self.assertEqual(version, False)
self.assertIs(version, self.im)

def test_scale_with_upscale_width(self):
version = scale_and_crop(self.im, 1500, "", "upscale")
Expand Down Expand Up @@ -82,7 +137,7 @@ def test_crop_width_and_height(self):
def test_crop_width_and_height_too_large_no_upscale(self):
# new width 1500 and height 1500 w. crop > false (upscale missing)
version = scale_and_crop(self.im, 1500, 1500, "crop")
self.assertEqual(version, False)
self.assertIs(version, self.im)

def test_crop_width_and_height_too_large_with_upscale(self):
version = scale_and_crop(self.im, 1500, 1500, "crop,upscale")
Expand Down

0 comments on commit e88c82f

Please sign in to comment.