FattView/fpdf/tests/cover/common.py
# -*- coding: utf-8 -*-
# common utilities for pyfpdf tests
# Note: 1) this file imported from both 2 and 3 version of python
# 2) import this file before import fpdf
# 3) assert this file in tests/cover folder
import sys, os, subprocess
PY3K = sys.version_info >= (3, 0)
basepath = os.path.abspath(os.path.join(__file__, "..", ".."))
RESHASH = "38db8db76e80a2e75f94d1df9eda307e"
# if PYFPDFTESTLOCAL is not set - use instaled pyfpdf version
PYFPDFTESTLOCAL = ("PYFPDFTESTLOCAL" in os.environ)
if PYFPDFTESTLOCAL:
sys.path = [os.path.join(basepath, "fpdf_local")] + sys.path
if PY3K:
#import common3 as _common
def tobytes(value):
return value.encode("latin1")
def frombytes(value):
return value.decode("latin1")
from hashlib import md5
unicode = str
else:
#import common2 as _common
def tobytes(value):
return value
def frombytes(value):
return value
try:
from hashlib import md5
except ImportError:
import md5
def exec_cmd(cmd):
"Execute command and return console output (stdout, stderr)"
obj = subprocess.Popen(cmd, \
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
std, err = obj.communicate()
return (frombytes(std), frombytes(err))
def start_by_ext(fn):
"Open file in associated progrom"
try:
try:
os.startfile(fn)
except WindowsError:
os.system("start " + fn)
except:
subprocess.call(["xdg-open", fn])
def writer(stream, items):
sep = ""
for item in items:
stream.write(sep)
sep = " "
if not isinstance(item, str):
item = str(item)
if not PY3K:
if not isinstance(item, unicode):
item = str(item)
stream.write(item)
stream.write("\n")
def log(*kw):
writer(sys.stdout, kw)
def err(*kw):
writer(sys.stderr, kw)
def test_putinfo(self):
"Replace info stamp with defaults for all automated test objects"
self._out('/Producer '+self._textstring('PyFPDF TEST http://pyfpdf.googlecode.com/'))
if hasattr(self,'title'):
self._out('/Title '+self._textstring(self.title))
if hasattr(self,'subject'):
self._out('/Subject '+self._textstring(self.subject))
if hasattr(self,'author'):
self._out('/Author '+self._textstring(self.author))
if hasattr (self,'keywords'):
self._out('/Keywords '+self._textstring(self.keywords))
if hasattr(self,'creator'):
self._out('/Creator '+self._textstring(self.creator))
self._out('/CreationDate '+self._textstring('D:19700101000000'))
def file_hash(fn):
"Calc MD5 hash for file"
md = md5()
f = open(fn, "rb")
try:
md.update(f.read())
finally:
f.close()
return md.hexdigest()
def read_cover_info(fn):
"Read cover test info"
f = open(fn, "rb")
da = {"res": []}
mark = "#PyFPDF-cover-test:"
encmark = "# -*- coding:"
enc = None
try:
hdr = False
for line in f.readlines():
if enc is None:
if line.decode("latin-1")[:len(encmark)] == unicode(encmark):
enc = line.decode("latin-1")[len(encmark):].strip()
if enc[-3:] == unicode("-*-"):
enc = enc[:-3].strip()
try:
line.decode(enc)
except:
enc = None
line = line.decode(enc or "UTF-8").strip()
if line[:len(mark)] == mark:
hdr = True
kv = line[len(mark):].split("=", 1)
if len(kv) == 2:
if kv[0] == "res":
da["res"].append(kv[1])
else:
da[kv[0]] = kv[1]
else:
if hdr and len(line) == 0:
break
finally:
f.close()
return da
def parse_test_args(args, deffn):
"Parse test args, return (fn, autotest)"
args = args[1:]
da = {}
da["fn"] = deffn
da["autotest"] = False
da["check"] = False
while len(args) > 0:
arg = args[0]
if arg == "--help":
log("Test usage: [--auto] [--check] [<outputname>]")
log(" --auto - no version and timestamp in file, do not open")
log(" --check - compare new file with stock")
log(" <outputname> - output filename, default \"%s\"" % deffn)
sys.exit(0)
if arg == "--auto":
da["autotest"] = True
elif arg == "--check":
da["check"] = True
else:
da["fn"] = arg
args = args[1:]
return da
def load_res_file(path):
items = {}
res = None
for line in open(path):
line = line.strip()
if line[:1] == "#":
continue
kv = line.split("=", 1)
if len(kv) != 2:
continue
if kv[0] == "res":
res = kv[1]
if res not in items:
items[res] = ["", []]
elif res is None:
continue
elif kv[0] == "hash":
items[res][0] = kv[1]
elif kv[0] == "tags":
items[res][1] += [kv[1].split(",")]
return items
def check_env(settings, args):
"Check test environment"
verbose = not args["autotest"]
# check python version
if PY3K:
if settings.get("python3", "yes") == "no":
# python 3 inacceptable
if verbose:
err("Python 3.x unsupported %s" % repr(sys.version_info))
else:
log("NOTFORPY3")
return False
else:
if settings.get("python2", "yes") == "no":
# python 2 inacceptable
if verbose:
err("Python 2.x unsupported %s" % repr(sys.version_info))
else:
log("NOTFORPY2")
return False
if settings.get("pil", "no") == "yes":
# import PIL
try:
try:
import Image
except:
from PIL import Image
except ImportError:
Image = None
if Image is None:
if verbose:
err("PIL or Pillow module is required")
else:
log("NOPIL")
return False
# check res
reslst = None
for res in settings.get("res", []):
if reslst is None:
# check
respath = os.path.join(basepath, "resources.txt")
if file_hash(respath) != RESHASH:
if verbose:
err("File resources.txt damaged (hash mismatch)")
else:
log("RESHASH")
return False
# load data
reslst = load_res_file(respath)
if res not in reslst:
err("Resource \"" + res + "\" not found")
if not verbose:
log("NORES")
return False
# check hash
respath = os.path.join(basepath, res)
hs = file_hash(respath)
if hs != reslst[res][0]:
err("Resource \"" + res + "\" damaged")
err(" read = %s" % hs)
err(" required = %s" % reslst[res][0])
if not verbose:
log("RESERR")
return False
return True
def check_result(settings, args):
check = True
if settings.get("fn"):
if args["check"]:
# compare with hash
hs = file_hash(args["fn"])
fhs = settings.get("hash", "")
if fhs != "" and hs != fhs:
check = False
err("Hash mismatch:")
err(" new = %s" % hs)
err(" required = %s" % fhs)
if args["autotest"]:
if check:
log("OK")
else:
log("HASHERROR")
else:
if settings.get("fn"):
start_by_ext(args["fn"])
else:
log("Test passed")
def testmain(fn, testfunc):
si = read_cover_info(fn)
da = parse_test_args(sys.argv, si.get("fn"))
if not check_env(si, da):
return
testfunc(da["fn"], da["autotest"] or da["check"])
check_result(si, da)