Skip to content

Commit

Permalink
vmoe the test suite back into libvips
Browse files Browse the repository at this point in the history
  • Loading branch information
jcupitt committed Jul 6, 2018
1 parent f0a44ce commit d510807
Show file tree
Hide file tree
Showing 45 changed files with 3,778 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,4 +1,5 @@
compile
.pytest_cache
a.out
*.log
*.trs
Expand Down
1 change: 1 addition & 0 deletions ChangeLog
Expand Up @@ -32,6 +32,7 @@
- pyramid builders have a choice of 2x2 shrinkers [harukizaemon]
- add `palette` option to pngsave [felixbuenemann]
- support writing string-valued fields via libexif
- paste in the test suite from pyvips

12/3/18 started 8.6.4
- better fitting of fonts with overhanging edges [Adrià]
Expand Down
5 changes: 5 additions & 0 deletions test/README.md
@@ -0,0 +1,5 @@
# libvips test suite

This is in two parts: a few simple bash scripts in this directory are run on
"make check", and a fancier Python test suite that's run by Travis on each
commit.
Binary file removed test/images/Landscape_6.jpg
Binary file not shown.
Empty file added test/test-suite/__init__.py
Empty file.
4 changes: 4 additions & 0 deletions test/test-suite/conftest.py
@@ -0,0 +1,4 @@
import sys
import os

sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers'))
232 changes: 232 additions & 0 deletions test/test-suite/helpers/helpers.py
@@ -0,0 +1,232 @@
# vim: set fileencoding=utf-8 :
# test helpers
import os
import tempfile
import pytest

import pyvips

IMAGES = os.path.join(os.path.dirname(__file__), os.pardir, 'images')
JPEG_FILE = os.path.join(IMAGES, "йцук.jpg")
SRGB_FILE = os.path.join(IMAGES, "sRGB.icm")
MATLAB_FILE = os.path.join(IMAGES, "sample.mat")
PNG_FILE = os.path.join(IMAGES, "sample.png")
TIF_FILE = os.path.join(IMAGES, "sample.tif")
OME_FILE = os.path.join(IMAGES, "multi-channel-z-series.ome.tif")
ANALYZE_FILE = os.path.join(IMAGES, "t00740_tr1_segm.hdr")
GIF_FILE = os.path.join(IMAGES, "cramps.gif")
WEBP_FILE = os.path.join(IMAGES, "1.webp")
EXR_FILE = os.path.join(IMAGES, "sample.exr")
FITS_FILE = os.path.join(IMAGES, "WFPC2u5780205r_c0fx.fits")
OPENSLIDE_FILE = os.path.join(IMAGES, "CMU-1-Small-Region.svs")
PDF_FILE = os.path.join(IMAGES, "ISO_12233-reschart.pdf")
CMYK_PDF_FILE = os.path.join(IMAGES, "cmyktest.pdf")
SVG_FILE = os.path.join(IMAGES, "vips-profile.svg")
SVGZ_FILE = os.path.join(IMAGES, "vips-profile.svgz")
SVG_GZ_FILE = os.path.join(IMAGES, "vips-profile.svg.gz")
GIF_ANIM_FILE = os.path.join(IMAGES, "cogs.gif")
DICOM_FILE = os.path.join(IMAGES, "dicom_test_image.dcm")
BMP_FILE = os.path.join(IMAGES, "MARBLES.BMP")

unsigned_formats = [pyvips.BandFormat.UCHAR,
pyvips.BandFormat.USHORT,
pyvips.BandFormat.UINT]
signed_formats = [pyvips.BandFormat.CHAR,
pyvips.BandFormat.SHORT,
pyvips.BandFormat.INT]
float_formats = [pyvips.BandFormat.FLOAT,
pyvips.BandFormat.DOUBLE]
complex_formats = [pyvips.BandFormat.COMPLEX,
pyvips.BandFormat.DPCOMPLEX]
int_formats = unsigned_formats + signed_formats
noncomplex_formats = int_formats + float_formats
all_formats = int_formats + float_formats + complex_formats

colour_colourspaces = [pyvips.Interpretation.XYZ,
pyvips.Interpretation.LAB,
pyvips.Interpretation.LCH,
pyvips.Interpretation.CMC,
pyvips.Interpretation.LABS,
pyvips.Interpretation.SCRGB,
pyvips.Interpretation.HSV,
pyvips.Interpretation.SRGB,
pyvips.Interpretation.YXY]
coded_colourspaces = [pyvips.Interpretation.LABQ]
mono_colourspaces = [pyvips.Interpretation.B_W]
sixteenbit_colourspaces = [pyvips.Interpretation.GREY16,
pyvips.Interpretation.RGB16]
all_colourspaces = colour_colourspaces + mono_colourspaces + \
coded_colourspaces + sixteenbit_colourspaces

max_value = {pyvips.BandFormat.UCHAR: 0xff,
pyvips.BandFormat.USHORT: 0xffff,
pyvips.BandFormat.UINT: 0xffffffff,
pyvips.BandFormat.CHAR: 0x7f,
pyvips.BandFormat.SHORT: 0x7fff,
pyvips.BandFormat.INT: 0x7fffffff,
pyvips.BandFormat.FLOAT: 1.0,
pyvips.BandFormat.DOUBLE: 1.0,
pyvips.BandFormat.COMPLEX: 1.0,
pyvips.BandFormat.DPCOMPLEX: 1.0}

sizeof_format = {pyvips.BandFormat.UCHAR: 1,
pyvips.BandFormat.USHORT: 2,
pyvips.BandFormat.UINT: 4,
pyvips.BandFormat.CHAR: 1,
pyvips.BandFormat.SHORT: 2,
pyvips.BandFormat.INT: 4,
pyvips.BandFormat.FLOAT: 4,
pyvips.BandFormat.DOUBLE: 8,
pyvips.BandFormat.COMPLEX: 8,
pyvips.BandFormat.DPCOMPLEX: 16}

rot45_angles = [pyvips.Angle45.D0,
pyvips.Angle45.D45,
pyvips.Angle45.D90,
pyvips.Angle45.D135,
pyvips.Angle45.D180,
pyvips.Angle45.D225,
pyvips.Angle45.D270,
pyvips.Angle45.D315]

rot45_angle_bonds = [pyvips.Angle45.D0,
pyvips.Angle45.D315,
pyvips.Angle45.D270,
pyvips.Angle45.D225,
pyvips.Angle45.D180,
pyvips.Angle45.D135,
pyvips.Angle45.D90,
pyvips.Angle45.D45]

rot_angles = [pyvips.Angle.D0,
pyvips.Angle.D90,
pyvips.Angle.D180,
pyvips.Angle.D270]

rot_angle_bonds = [pyvips.Angle.D0,
pyvips.Angle.D270,
pyvips.Angle.D180,
pyvips.Angle.D90]


# an expanding zip ... if either of the args is a scalar or a one-element list,
# duplicate it down the other side
def zip_expand(x, y):
# handle singleton list case
if isinstance(x, list) and len(x) == 1:
x = x[0]
if isinstance(y, list) and len(y) == 1:
y = y[0]

if isinstance(x, list) and isinstance(y, list):
return list(zip(x, y))
elif isinstance(x, list):
return [[i, y] for i in x]
elif isinstance(y, list):
return [[x, j] for j in y]
else:
return [[x, y]]


# run a 1-ary function on a thing -- loop over elements if the
# thing is a list
def run_fn(fn, x):
if isinstance(x, list):
return [fn(i) for i in x]
else:
return fn(x)


# make a temp filename with the specified suffix and in the
# specified directory
def temp_filename(directory, suffix):
temp_name = next(tempfile._get_candidate_names())
filename = os.path.join(directory, temp_name + suffix)

return filename


# test for an operator exists
def have(name):
return pyvips.type_find("VipsOperation", name) != 0


def skip_if_no(operation_name):
return pytest.mark.skipif(not have(operation_name),
reason='no {}, skipping test'.format(operation_name))


# run a 2-ary function on two things -- loop over elements pairwise if the
# things are lists
def run_fn2(fn, x, y):
if isinstance(x, pyvips.Image) or isinstance(y, pyvips.Image):
return fn(x, y)
elif isinstance(x, list) or isinstance(y, list):
return [fn(i, j) for i, j in zip_expand(x, y)]
else:
return fn(x, y)


# test a pair of things which can be lists for approx. equality
def assert_almost_equal_objects(a, b, threshold=0.0001, msg=''):
# print 'assertAlmostEqualObjects %s = %s' % (a, b)
assert all([pytest.approx(x, abs=threshold) == y
for x, y in zip_expand(a, b)]), msg


# test a pair of things which can be lists for equality
def assert_equal_objects(a, b, msg=''):
# print 'assertEqualObjects %s = %s' % (a, b)
assert all([x == y for x, y in zip_expand(a, b)]), msg


# test a pair of things which can be lists for difference less than a
# threshold
def assert_less_threshold(a, b, diff):
assert all([abs(x - y) < diff for x, y in zip_expand(a, b)])


# run a function on an image and on a single pixel, the results
# should match
def run_cmp(message, im, x, y, fn):
a = im(x, y)
v1 = fn(a)
im2 = fn(im)
v2 = im2(x, y)
assert_almost_equal_objects(v1, v2, msg=message)


# run a function on an image,
# 50,50 and 10,10 should have different values on the test image
def run_image(message, im, fn):
run_cmp(message, im, 50, 50, fn)
run_cmp(message, im, 10, 10, fn)


# run a function on (image, constant), and on (constant, image).
# 50,50 and 10,10 should have different values on the test image
def run_const(message, fn, im, c):
run_cmp(message, im, 50, 50, lambda x: run_fn2(fn, x, c))
run_cmp(message, im, 50, 50, lambda x: run_fn2(fn, c, x))
run_cmp(message, im, 10, 10, lambda x: run_fn2(fn, x, c))
run_cmp(message, im, 10, 10, lambda x: run_fn2(fn, c, x))


# run a function on a pair of images and on a pair of pixels, the results
# should match
def run_cmp2(message, left, right, x, y, fn):
a = left(x, y)
b = right(x, y)
v1 = fn(a, b)
after = fn(left, right)
v2 = after(x, y)
assert_almost_equal_objects(v1, v2, msg=message)


# run a function on a pair of images
# 50,50 and 10,10 should have different values on the test image
def run_image2(message, left, right, fn):
run_cmp2(message, left, right, 50, 50,
lambda x, y: run_fn2(fn, x, y))
run_cmp2(message, left, right, 10, 10,
lambda x, y: run_fn2(fn, x, y))
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file added test/test-suite/images/MARBLES.BMP
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes

0 comments on commit d510807

Please sign in to comment.