Pillow/Tests/tester.py

383 lines
9.5 KiB
Python
Raw Normal View History

from __future__ import print_function
# require that deprecation warnings are triggered
2013-05-22 20:26:41 +04:00
import warnings
warnings.simplefilter('default')
# temporarily turn off resource warnings that warn about unclosed
# files in the test scripts.
try:
2014-04-08 18:17:10 +04:00
warnings.filterwarnings("ignore", category=ResourceWarning)
except NameError:
2014-04-08 18:17:10 +04:00
# we expect a NameError on py2.x, since it doesn't have ResourceWarnings.
pass
2013-05-22 20:26:41 +04:00
import sys
2014-04-08 18:17:10 +04:00
py3 = (sys.version_info >= (3, 0))
# some test helpers
_target = None
_tempfiles = []
_logfile = None
2014-04-08 18:17:10 +04:00
def success():
import sys
success.count += 1
if _logfile:
print(sys.argv[0], success.count, failure.count, file=_logfile)
2014-01-24 09:06:33 +04:00
return True
2014-04-08 18:17:10 +04:00
def failure(msg=None, frame=None):
2014-04-08 18:17:10 +04:00
import sys
import linecache
failure.count += 1
if _target:
if frame is None:
frame = sys._getframe()
while frame.f_globals.get("__name__") != _target.__name__:
frame = frame.f_back
location = (frame.f_code.co_filename, frame.f_lineno)
prefix = "%s:%d: " % location
line = linecache.getline(*location)
print(prefix + line.strip() + " failed:")
if msg:
print("- " + msg)
if _logfile:
print(sys.argv[0], success.count, failure.count, file=_logfile)
2014-01-24 09:06:33 +04:00
return False
success.count = failure.count = 0
2014-04-08 18:17:10 +04:00
# predicates
def assert_true(v, msg=None):
if v:
success()
else:
failure(msg or "got %r, expected true value" % v)
2014-04-08 18:17:10 +04:00
def assert_false(v, msg=None):
if v:
failure(msg or "got %r, expected false value" % v)
else:
success()
2014-04-08 18:17:10 +04:00
def assert_equal(a, b, msg=None):
if a == b:
success()
else:
failure(msg or "got %r, expected %r" % (a, b))
2014-04-08 18:17:10 +04:00
def assert_almost_equal(a, b, msg=None, eps=1e-6):
if abs(a-b) < eps:
success()
else:
failure(msg or "got %r, expected %r" % (a, b))
2014-04-08 18:17:10 +04:00
2013-10-01 01:10:58 +04:00
def assert_deep_equal(a, b, msg=None):
try:
if len(a) == len(b):
2014-04-08 18:17:10 +04:00
if all([x == y for x, y in zip(a, b)]):
2013-10-01 01:10:58 +04:00
success()
else:
2014-04-08 18:17:10 +04:00
failure(msg or "got %s, expected %s" % (a, b))
2013-10-01 01:10:58 +04:00
else:
failure(msg or "got length %s, expected %s" % (len(a), len(b)))
2013-10-01 01:10:58 +04:00
except:
2014-04-08 18:17:10 +04:00
assert_equal(a, b, msg)
2013-10-01 01:10:58 +04:00
2014-04-11 15:53:33 +04:00
def assert_greater(a, b, msg=None):
if a > b:
success()
else:
2014-04-14 00:16:01 +04:00
failure(msg or "%r unexpectedly not greater than %r" % (a, b))
2014-04-11 15:53:33 +04:00
def assert_greater_equal(a, b, msg=None):
if a >= b:
success()
else:
2014-04-14 00:16:01 +04:00
failure(
msg or "%r unexpectedly not greater than or equal to %r" % (a, b))
2014-04-11 15:53:33 +04:00
def assert_less(a, b, msg=None):
if a < b:
success()
else:
2014-04-14 00:16:01 +04:00
failure(msg or "%r unexpectedly not less than %r" % (a, b))
2014-04-11 15:53:33 +04:00
def assert_less_equal(a, b, msg=None):
if a <= b:
success()
else:
2014-04-14 00:16:01 +04:00
failure(
msg or "%r unexpectedly not less than or equal to %r" % (a, b))
def assert_is_instance(a, b, msg=None):
if isinstance(a, b):
success()
else:
failure(msg or "got %r, expected %r" % (type(a), b))
def assert_in(a, b, msg=None):
if a in b:
success()
else:
failure(msg or "%r unexpectedly not in %r" % (a, b))
2014-04-11 15:53:33 +04:00
def assert_match(v, pattern, msg=None):
import re
if re.match(pattern, v):
success()
else:
failure(msg or "got %r, doesn't match pattern %r" % (v, pattern))
2014-04-08 18:17:10 +04:00
def assert_exception(exc_class, func):
2014-04-08 18:17:10 +04:00
import sys
import traceback
try:
func()
except exc_class:
success()
except:
failure("expected %r exception, got %r" % (
exc_class.__name__, sys.exc_info()[0].__name__))
traceback.print_exc()
else:
failure("expected %r exception, got no exception" % exc_class.__name__)
2014-04-08 18:17:10 +04:00
def assert_no_exception(func):
2014-04-08 18:17:10 +04:00
import sys
import traceback
try:
func()
except:
failure("expected no exception, got %r" % sys.exc_info()[0].__name__)
traceback.print_exc()
else:
success()
2014-04-08 18:17:10 +04:00
def assert_warning(warn_class, func):
# note: this assert calls func three times!
import warnings
2014-04-08 18:17:10 +04:00
2014-03-30 20:25:52 +04:00
def warn_error(message, category=UserWarning, **options):
raise category(message)
2014-04-08 18:17:10 +04:00
2014-03-30 20:25:52 +04:00
def warn_ignore(message, category=UserWarning, **options):
pass
warn = warnings.warn
result = None
try:
warnings.warn = warn_ignore
assert_no_exception(func)
result = func()
warnings.warn = warn_error
assert_exception(warn_class, func)
finally:
2014-04-08 18:17:10 +04:00
warnings.warn = warn # restore
return result
# helpers
from io import BytesIO
2014-04-08 18:17:10 +04:00
def fromstring(data):
from PIL import Image
return Image.open(BytesIO(data))
2014-04-08 18:17:10 +04:00
def tostring(im, format, **options):
out = BytesIO()
im.save(out, format, **options)
return out.getvalue()
2014-04-08 18:17:10 +04:00
def lena(mode="RGB", cache={}):
from PIL import Image
im = cache.get(mode)
if im is None:
if mode == "RGB":
im = Image.open("Images/lena.ppm")
elif mode == "F":
im = lena("L").convert(mode)
elif mode[:4] == "I;16":
im = lena("I").convert(mode)
else:
im = lena("RGB").convert(mode)
cache[mode] = im
return im
2014-04-08 18:17:10 +04:00
def assert_image(im, mode, size, msg=None):
if mode is not None and im.mode != mode:
failure(msg or "got mode %r, expected %r" % (im.mode, mode))
elif size is not None and im.size != size:
failure(msg or "got size %r, expected %r" % (im.size, size))
else:
success()
2014-04-08 18:17:10 +04:00
def assert_image_equal(a, b, msg=None):
if a.mode != b.mode:
failure(msg or "got mode %r, expected %r" % (a.mode, b.mode))
elif a.size != b.size:
failure(msg or "got size %r, expected %r" % (a.size, b.size))
elif a.tobytes() != b.tobytes():
failure(msg or "got different content")
# generate better diff?
else:
success()
2014-04-08 18:17:10 +04:00
def assert_image_similar(a, b, epsilon, msg=None):
epsilon = float(epsilon)
if a.mode != b.mode:
return failure(msg or "got mode %r, expected %r" % (a.mode, b.mode))
elif a.size != b.size:
return failure(msg or "got size %r, expected %r" % (a.size, b.size))
diff = 0
2013-03-23 08:25:37 +04:00
try:
ord(b'0')
2014-04-08 18:17:10 +04:00
for abyte, bbyte in zip(a.tobytes(), b.tobytes()):
2013-03-23 08:25:37 +04:00
diff += abs(ord(abyte)-ord(bbyte))
except:
2014-04-08 18:17:10 +04:00
for abyte, bbyte in zip(a.tobytes(), b.tobytes()):
2013-03-23 08:25:37 +04:00
diff += abs(abyte-bbyte)
ave_diff = float(diff)/(a.size[0]*a.size[1])
if epsilon < ave_diff:
2014-04-08 18:17:10 +04:00
return failure(
msg or "average pixel value difference %.4f > epsilon %.4f" % (
ave_diff, epsilon))
else:
2014-01-24 09:06:33 +04:00
return success()
2014-04-08 18:17:10 +04:00
def tempfile(template, *extra):
2014-04-08 18:17:10 +04:00
import os
import os.path
import sys
import tempfile
files = []
root = os.path.join(tempfile.gettempdir(), 'pillow-tests')
try:
os.mkdir(root)
except OSError:
pass
for temp in (template,) + extra:
assert temp[:5] in ("temp.", "temp_")
name = os.path.basename(sys.argv[0])
name = temp[:4] + os.path.splitext(name)[0][4:]
name = name + "_%d" % len(_tempfiles) + temp[4:]
name = os.path.join(root, name)
files.append(name)
_tempfiles.extend(files)
return files[0]
2014-04-08 18:17:10 +04:00
# test runner
def run():
global _target, _tests, run
2014-04-08 18:17:10 +04:00
import sys
import traceback
_target = sys.modules["__main__"]
2014-04-08 18:17:10 +04:00
run = None # no need to run twice
tests = []
for name, value in list(vars(_target).items()):
if name[:5] == "test_" and type(value) is type(success):
tests.append((value.__code__.co_firstlineno, name, value))
2014-04-08 18:17:10 +04:00
tests.sort() # sort by line
for lineno, name, func in tests:
try:
_tests = []
func()
for func, args in _tests:
func(*args)
except:
t, v, tb = sys.exc_info()
tb = tb.tb_next
if tb:
failure(frame=tb.tb_frame)
traceback.print_exception(t, v, tb)
else:
print("%s:%d: cannot call test function: %s" % (
sys.argv[0], lineno, v))
failure.count += 1
2014-04-08 18:17:10 +04:00
def yield_test(function, *args):
# collect delayed/generated tests
_tests.append((function, args))
2014-04-08 18:17:10 +04:00
def skip(msg=None):
import os
print("skip")
2014-04-08 18:17:10 +04:00
os._exit(0) # don't run exit handlers
def ignore(pattern):
"""Tells the driver to ignore messages matching the pattern, for the
duration of the current test."""
print('ignore: %s' % pattern)
2014-04-08 18:17:10 +04:00
def _setup():
global _logfile
2014-04-08 18:17:10 +04:00
import sys
if "--coverage" in sys.argv:
# Temporary: ignore PendingDeprecationWarning from Coverage (Py3.4)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
import coverage
cov = coverage.coverage(auto_data=True, include="PIL/*")
cov.start()
def report():
if run:
run()
if success.count and not failure.count:
print("ok")
# only clean out tempfiles if test passed
2014-04-08 18:17:10 +04:00
import os
import os.path
import tempfile
for file in _tempfiles:
try:
os.remove(file)
except OSError:
2014-04-08 18:17:10 +04:00
pass # report?
temp_root = os.path.join(tempfile.gettempdir(), 'pillow-tests')
try:
os.rmdir(temp_root)
except OSError:
pass
2014-04-08 18:17:10 +04:00
import atexit
atexit.register(report)
if "--log" in sys.argv:
_logfile = open("test.log", "a")
_setup()