189 lines
6.4 KiB
Python
189 lines
6.4 KiB
Python
import sys, os
|
|
import re
|
|
import unittest
|
|
import traceback
|
|
import pywin32_testutil
|
|
|
|
# A list of demos that depend on user-interface of *any* kind. Tests listed
|
|
# here are not suitable for unattended testing.
|
|
ui_demos = """GetSaveFileName print_desktop win32cred_demo win32gui_demo
|
|
win32gui_dialog win32gui_menu win32gui_taskbar
|
|
win32rcparser_demo winprocess win32console_demo
|
|
win32clipboard_bitmapdemo
|
|
win32gui_devicenotify
|
|
NetValidatePasswordPolicy""".split()
|
|
# Other demos known as 'bad' (or at least highly unlikely to work)
|
|
# cerapi: no CE module is built (CE via pywin32 appears dead)
|
|
# desktopmanager: hangs (well, hangs for 60secs or so...)
|
|
# EvtSubscribe_*: must be run together
|
|
bad_demos = """cerapi desktopmanager win32comport_demo
|
|
EvtSubscribe_pull EvtSubscribe_push
|
|
""".split()
|
|
|
|
argvs = {
|
|
"rastest": ("-l",),
|
|
}
|
|
|
|
no_user_interaction = False
|
|
|
|
# re to pull apart an exception line into the exception type and the args.
|
|
re_exception = re.compile("([a-zA-Z0-9_.]*): (.*)$")
|
|
def find_exception_in_output(data):
|
|
have_traceback = False
|
|
for line in data.splitlines():
|
|
line = line.decode('ascii') # not sure what the correct encoding is...
|
|
if line.startswith("Traceback ("):
|
|
have_traceback = True
|
|
continue
|
|
if line.startswith(" "):
|
|
continue
|
|
if have_traceback:
|
|
# first line not starting with a space since the traceback.
|
|
# must be the exception!
|
|
m = re_exception.match(line)
|
|
if m:
|
|
exc_type, args = m.groups()
|
|
# get hacky - get the *real* exception object from the name.
|
|
bits = exc_type.split(".", 1)
|
|
if len(bits) > 1:
|
|
mod = __import__(bits[0])
|
|
exc = getattr(mod, bits[1])
|
|
else:
|
|
# probably builtin
|
|
exc = eval(bits[0])
|
|
else:
|
|
# hrm - probably just an exception with no args
|
|
try:
|
|
exc = eval(line.strip())
|
|
args = "()"
|
|
except:
|
|
return None
|
|
# try and turn the args into real args.
|
|
try:
|
|
args = eval(args)
|
|
except:
|
|
pass
|
|
if not isinstance(args, tuple):
|
|
args = (args,)
|
|
# try and instantiate the exception.
|
|
try:
|
|
ret = exc(*args)
|
|
except:
|
|
ret = None
|
|
return ret
|
|
# apparently not - keep looking...
|
|
have_traceback = False
|
|
|
|
|
|
class TestRunner:
|
|
def __init__(self, argv):
|
|
self.argv = argv
|
|
self.__name__ = "Test Runner for cmdline {}".format(argv)
|
|
|
|
def __call__(self):
|
|
import subprocess
|
|
p = subprocess.Popen(self.argv,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT)
|
|
output, _ = p.communicate()
|
|
rc = p.returncode
|
|
|
|
if rc:
|
|
base = os.path.basename(self.argv[1])
|
|
# See if we can detect and reconstruct an exception in the output.
|
|
reconstituted = find_exception_in_output(output)
|
|
if reconstituted is not None:
|
|
raise reconstituted
|
|
raise AssertionError("%s failed with exit code %s. Output is:\n%s" % (base, rc, output))
|
|
|
|
def get_demo_tests():
|
|
import win32api
|
|
ret = []
|
|
demo_dir = os.path.abspath(os.path.join(os.path.dirname(win32api.__file__), "Demos"))
|
|
assert os.path.isdir(demo_dir), demo_dir
|
|
for name in os.listdir(demo_dir):
|
|
base, ext = os.path.splitext(name)
|
|
if base in ui_demos and no_user_interaction:
|
|
continue
|
|
# Skip any other files than .py and bad tests in any case
|
|
if ext != ".py" or base in bad_demos:
|
|
continue
|
|
argv = (sys.executable, os.path.join(demo_dir, base+".py")) + \
|
|
argvs.get(base, ())
|
|
ret.append(unittest.FunctionTestCase(TestRunner(argv), description="win32/demos/" + name))
|
|
return ret
|
|
|
|
def import_all():
|
|
# Some hacks for import order - dde depends on win32ui
|
|
try:
|
|
import win32ui
|
|
except ImportError:
|
|
pass # 'what-ev-a....'
|
|
|
|
import win32api
|
|
dir = os.path.dirname(win32api.__file__)
|
|
num = 0
|
|
is_debug = os.path.basename(win32api.__file__).endswith("_d")
|
|
for name in os.listdir(dir):
|
|
base, ext = os.path.splitext(name)
|
|
if (ext==".pyd") and \
|
|
name != "_winxptheme.pyd" and \
|
|
(is_debug and base.endswith("_d") or \
|
|
not is_debug and not base.endswith("_d")):
|
|
try:
|
|
__import__(base)
|
|
except:
|
|
print(("FAILED to import", name))
|
|
raise
|
|
num += 1
|
|
|
|
def suite():
|
|
# Loop over all .py files here, except me :)
|
|
try:
|
|
me = __file__
|
|
except NameError:
|
|
me = sys.argv[0]
|
|
me = os.path.abspath(me)
|
|
files = os.listdir(os.path.dirname(me))
|
|
suite = unittest.TestSuite()
|
|
suite.addTest(unittest.FunctionTestCase(import_all))
|
|
for file in files:
|
|
base, ext = os.path.splitext(file)
|
|
if ext=='.py' and os.path.basename(me) != file:
|
|
try:
|
|
mod = __import__(base)
|
|
except:
|
|
print("FAILED to import test module %r" % base)
|
|
traceback.print_exc()
|
|
continue
|
|
if hasattr(mod, "suite"):
|
|
test = mod.suite()
|
|
else:
|
|
test = unittest.defaultTestLoader.loadTestsFromModule(mod)
|
|
suite.addTest(test)
|
|
for test in get_demo_tests():
|
|
suite.addTest(test)
|
|
return suite
|
|
|
|
|
|
class CustomLoader(pywin32_testutil.TestLoader):
|
|
def loadTestsFromModule(self, module):
|
|
return self.fixupTestsForLeakTests(suite())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="Test runner for PyWin32/win32")
|
|
parser.add_argument("-no-user-interaction",
|
|
default=no_user_interaction,
|
|
action='store_true',
|
|
help="Run all tests without user interaction")
|
|
|
|
parsed_args, remains = parser.parse_known_args()
|
|
|
|
no_user_interaction = parsed_args.no_user_interaction
|
|
|
|
sys.argv = [sys.argv[0]] + remains
|
|
|
|
pywin32_testutil.testmain(testLoader=CustomLoader())
|