123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- 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())
|