#!/usr/bin/env python # -*- coding: utf-8 -*- import os, sys import cover import shutil import traceback def search_python_posix(): lst = [] path = os.environ.get("PATH") for item in path.split(":"): try: for interp in os.listdir(item): if interp[:6] != "python": continue if interp[-7:] == "-config": continue fp = os.path.join(item, interp) # test if already in list same = False for lidx, l_interp in enumerate(lst): if os.path.samefile(l_interp, fp): same = True # use shorter name if len(l_interp) < len(fp): lst[lidx] = fp break if same: continue lst.append(fp) except OSError: pass return lst def search_python_win(): lst = [] try: try: import _winreg as winreg except ImportError: import winreg def findreg(key, lst): PATH = "SOFTWARE\\Python\\PythonCore" try: rl = winreg.OpenKey(key, PATH) except WindowsError: return lst try: for i in range(winreg.QueryInfoKey(rl)[0]): ver = winreg.EnumKey(rl, i) rv = winreg.QueryValue(key, PATH + "\\" + ver + "\\InstallPath") fp = os.path.join(rv, "python.exe") #print fp if os.path.exists(fp) and not fp in lst: lst.append(fp) except WindowsError: pass return lst lst = findreg(winreg.HKEY_LOCAL_MACHINE, lst) lst = findreg(winreg.HKEY_CURRENT_USER, lst) except: traceback.print_exc(file = sys.stdout) # fallback cover.log("Search python at system drive") try: path = os.environ.get("SystemDrive", "C:") for item in os.listdir(path): if item[:6].lower() != "python": continue fp = os.path.join(path, item, "python.exe") if os.path.exists(fp) and not fp in lst: lst.append(fp) except: traceback.print_exc(file = sys.stdout) return lst def search_python(): if sys.platform.startswith("linux"): lst = search_python_posix() elif sys.platform.startswith("win"): lst = search_python_win() else: lst = search_python_posix() if len(lst) == 0: # fallback lst.append(sys.executable) return lst def find_python_version(pylst): lst = [] ids = [] for interp in pylst: try: std, err = cover.exec_cmd([interp, "-V"]) version = err.strip() if not version: # python 3.4+ version = std.strip() if version[:6] == "Python": shver = version[6:].strip().replace(" ", "-") nid = shver nidn = 0 while nid in ids: nidn += 1 nid = shver + "-%d" % nidn ids.append(nid) lst.append((interp, nid, version)) else: cover.err("Not a python", version) # no python found continue except: traceback.print_exc(file = sys.stdout) return lst def search_tests(): base = os.path.join(cover.basepath, "cover") lst = [] for item in os.listdir(base): if item[:5] != "test_" or item[-3:] != ".py": continue lst.append(os.path.join(base, item)) lst.sort() return lst def do_test_one(testfile, interp, info, dest): path = interp[0] nid = interp[1] destpath = dest[0] destenv = dest[1] # check PIL if info.get("pil", "no") == "yes": if destenv.get("pil", "no") != "yes": return ("skip", "no PIL or PIllow found") # check python version tool2to3 = (info.get("2to3", "no") == "yes") py2 = (info.get("python2", "yes") == "yes") py3 = (info.get("python3", "yes") == "yes") plat = info.get("platform", "*") if plat == "": plat = "*" if plat != "*": plats = plat.split(",") accept = False for plat in plats: if sys.platform == plat: accept = True break if not accept: return ("skip", "not for \"" + sys.platform + "\"") copy = False if nid[:2] == "3.": if not py3: return ("skip", "not for python 3") if not tool2to3: copy = True else: return ("unimplemented", "todo") if nid[:2] == "2.": if not py2: return ("skip", "not for python 2") copy = True # check if fpdf instaled if destenv.get("ver", "None") == "None": return ("nofpdf", "") # copy files testname = os.path.basename(testfile) testfmt = info.get("format", "raw") newfile = os.path.join(destpath, testname) newres = os.path.join(destpath, info.get("fn", testname + "." + testfmt.lower())) if copy: shutil.copy(testfile, destpath) # start execution std, err = cover.exec_cmd([path, "-B", newfile, "--check", "--auto", newres]) f = open(os.path.join(destpath, "testlog.txt"), "a") f.write("#" * 40 + "\n") f.write(testname + "\n") f.write("=" * 40 + "\n") f.write(std) f.write("-" * 40 + "\n") f.write(err) f.close() answ = std.strip() if answ.find("\n") >= 0 or len(answ) == 0: return ("fail", "bad output") else: if answ == "HASHERROR": # get new hash nh = "" for line in err.split("\n"): line = line.strip() if line[:5] == "new =": nh = line[5:].strip() return ("hasherror", nh) return (answ.lower(), "") def prepare_dest(interp): destpath = os.path.join(cover.basepath, "out-" + interp[1]) if not os.path.exists(destpath): os.makedirs(destpath) # copy common set src = os.path.join(cover.basepath, "cover") shutil.copy(os.path.join(src, "common.py"), destpath) shutil.copy(os.path.join(src, "checkenv.py"), destpath) f = open(os.path.join(destpath, "testlog.txt"), "w") f.write("Version: " + interp[1] + "\n") f.write("Path: " + interp[0] + "\n") f.write(str(interp[2:]) + "\n") # run checkenv std, err = cover.exec_cmd([interp[0], "-B", os.path.join(destpath, "checkenv.py")]) env = {} if len(err.strip()) == 0: # OK f.write("Check environment - ok:\n") f.write(std) lineno = 0 for line in std.split("\n"): lineno += 1 line = line.strip() if lineno == 1: if line != "CHECK": break line = line.strip() kv = line.split("=", 1) if len(kv) == 2: env[kv[0].lower().strip()] = kv[1].strip() else: f.write("ERROR:\n") f.write(err) f.close() return (destpath, env) def do_test(testfile, interps, dests, stats, hint = ""): cover.log("Test", hint, ":", os.path.basename(testfile)) info = cover.read_cover_info(testfile) resall = "" # prepare # do tests hasherr = [] for interp in interps: if len(interps) < 6: resall += (interp[1] + " - ") res, desc = do_test_one(testfile, interp, info, dests[interp[1]]) if res == "hasherror": hasherr.append(desc) #cover.log("HASH =", desc) # update statistic stats["_"]["_"] += 1 stats["_"][res] = stats["_"].get(res, 0) + 1 stats[interp[1]]["_"] += 1 stats[interp[1]][res] = stats[interp[1]].get(res, 0) + 1 resall += (res + " " * 10)[:6].upper() resall += " " cover.log(resall) # test if all hash if len(interps) == len(hasherr): cover.err("All hashes wrong") def print_interps(interps): cover.log(">> Interpretors:", len(interps)) dests = {} stats = {"_": {"_": 0}} for idx, interp in enumerate(interps): cover.log("%d) %s - %s" % (idx + 1, interp[1], interp[0])) cover.log() def do_all_test(interps, tests): print_interps(interps) dests = {} stats = {"_": {"_": 0}} for idx, interp in enumerate(interps): dests[interp[1]] = prepare_dest(interp) stats[interp[1]] = {"_": 0} cover.log(">> Tests:", len(tests)) for idx, test in enumerate(tests): do_test(test, interps, dests, stats, "%d / %d" % (idx + 1, len(tests))) cover.log() cover.log(">> Statistics:") def stat_str(stat): keys = list(stat.keys()) keys.sort() st = "total - %d" % stat["_"] for key in keys: if key == "_": continue st += (", %s - %d" % (key, stat[key])) return st for interp in interps: cover.log(interp[1] + ":", stat_str(stats[interp[1]])) cover.log("-"*10) cover.log("All:", stat_str(stats["_"])) # check if no FPDF at all total = stats["_"]["_"] fpdf = stats["_"].get("nofpdf", 0) skip = stats["_"].get("skip", 0) if skip == total: cover.log("All tests skipped. Install some modules (PIL, PyBIDI, Gluon etc)") elif fpdf + skip == total: hint_prepare() def list_tests(): tst = search_tests() cover.log(">> Tests:", len(tst)) for idx, test in enumerate(tst): test = os.path.basename(test) if test[:5].lower() == "test_": test = test[5:] if test[-3:].lower() == ".py": test = test[:-3] cover.log("%d) %s" % (idx + 1, test)) cover.log() def usage(): cover.log("Usage: runtest.py [...]") cover.log(" --listtests - list all tests") cover.log(" --listinterps - list all availiable interpretors") cover.log(" --test issuexx - add test issuexx") cover.log(" --test @file - add test from file") cover.log(" --interp path - test against specified interpretors") cover.log(" --interp @file - read interpretors list from file") cover.log(" --downloadfonts - download font set") cover.log(" --help - this page") def hint_prepare(): if cover.PYFPDFTESTLOCAL: if sys.platform.startswith("win"): prefix = "" suffix = ".bat" else: prefix = "./" suffix = ".sh" cover.log("*** Please, prepare local copy for tests") cover.log("*** " + prefix + "prepare_local" + suffix) else: cover.log("*** Please, install PyFPDF with") cover.log("*** python setup.py install") cover.log("*** or set PYFPDFTESTLOCAL variable to use local copy") if sys.platform.startswith("win"): cover.log("*** set PYFPDFTESTLOCAL=1") else: cover.log("*** export PYFPDFTESTLOCAL=1") def read_list(fn): f = open(fn, "r") try: return f.readlines() finally: f.close() def hasher(path, args): tags = [] while len(args): arg = args[0] args = args[1:] if arg == "--tag": if len(args) == 0: cover.log("Param without value") return value = args[0] args = args[1:] if value not in tags: tags.append(value) else: cover.log("Unknown param") return lst = [] if os.path.isdir(path): files = [(x.lower(), x) for x in os.listdir(path)] files.sort() for s, item in files: fp = os.path.join(path, item) # clear path bp = fp if sys.platform.startswith("win"): bp = fp.replace("\\", "/") lst += [[bp, cover.file_hash(fp)]] else: lst = [[path, cover.file_hash(path)]] for item, hs in lst: cover.log("res=" + item) cover.log("hash=" + hs) cover.log("tags=" + ",".join(tags)) cover.log() def download_fonts(): URL = "http://pyfpdf.googlecode.com/files/fpdf_unicode_font_pack.zip" fntdir = os.path.join(cover.basepath, "font") zippath = os.path.join(cover.basepath, URL.split('/')[-1]) if not os.path.exists(fntdir): os.makedirs(fntdir) if not os.path.exists(zippath): import urllib2 u = urllib2.urlopen(URL) meta = u.info() file_size = int(meta.getheaders("Content-Length")[0]) cover.log("Downloading:", file_size, "bytes") f = open(zippath, "wb") file_size_dl = 0 while True: buff = u.read(64 * 1024) if not buff: break file_size_dl += len(buff) f.write(buff) cover.log(" ", file_size_dl * 100. / file_size, "%") f.close() # unpack cover.log("Extracting") import zipfile fh = open(zippath, "rb") z = zipfile.ZipFile(fh) for name in z.namelist(): if name[:5] != "font/": continue if name[5:].find("/") >= 0: continue cover.log(" ", name[5:]) outfile = open(os.path.join(fntdir, name[5:]), "wb") outfile.write(z.read(name)) outfile.close() cover.log("Done") def main(): cover.log("Test PyFPDF") testsn = [] interpsn = [] args = sys.argv[1:] while len(args): arg = args[0] args = args[1:] if arg == "--hash": if len(args) == 0: cover.log("Param without value") return usage() return hasher(args[0], args[1:]) if arg == "--help": return usage() elif arg == "--test": if len(args) > 0: value = args[0] args = args[1:] else: cover.log("Param without value") return usage() if value[:1] == "@": # from file testsn += read_list(value[1:]) else: testsn.append(value) elif arg == "--interp": if len(args) > 0: value = args[0] args = args[1:] else: cover.log("Param without value") return usage() if value[:1] == "@": # from file interpsn += read_list(value[1:]) else: interpsn.append(value) elif arg == "--listtests": return list_tests() elif arg == "--listinterps": return print_interps(find_python_version(search_python())) elif arg == "--downloadfonts": return download_fonts() else: cover.log("Unknown param") return usage() if len(testsn) == 0: tests = search_tests() else: # cheack all tests tests = [] for test in testsn: test = test.strip() fn = os.path.join(cover.basepath, "cover", "test_" + test + ".py") if os.path.exists(fn): tests.append(fn) else: cover.err("Test \"%s\" not found" % test) return if len(interpsn) == 0: interps = find_python_version(search_python()) else: # cheack all tests interps = [] for interp in interpsn: fn = os.path.abspath(interp) if os.path.exists(fn): interps.append(fn) else: cover.err("Interpretor \"%s\" not found" % test) return interps = find_python_version(interps) do_all_test(interps, tests) if __name__ == "__main__": main()