testall.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import sys, os
  2. import re
  3. import unittest
  4. import traceback
  5. import pywin32_testutil
  6. # A list of demos that depend on user-interface of *any* kind. Tests listed
  7. # here are not suitable for unattended testing.
  8. ui_demos = """GetSaveFileName print_desktop win32cred_demo win32gui_demo
  9. win32gui_dialog win32gui_menu win32gui_taskbar
  10. win32rcparser_demo winprocess win32console_demo
  11. win32clipboard_bitmapdemo
  12. win32gui_devicenotify
  13. NetValidatePasswordPolicy""".split()
  14. # Other demos known as 'bad' (or at least highly unlikely to work)
  15. # cerapi: no CE module is built (CE via pywin32 appears dead)
  16. # desktopmanager: hangs (well, hangs for 60secs or so...)
  17. # EvtSubscribe_*: must be run together
  18. bad_demos = """cerapi desktopmanager win32comport_demo
  19. EvtSubscribe_pull EvtSubscribe_push
  20. """.split()
  21. argvs = {
  22. "rastest": ("-l",),
  23. }
  24. no_user_interaction = False
  25. # re to pull apart an exception line into the exception type and the args.
  26. re_exception = re.compile("([a-zA-Z0-9_.]*): (.*)$")
  27. def find_exception_in_output(data):
  28. have_traceback = False
  29. for line in data.splitlines():
  30. line = line.decode('ascii') # not sure what the correct encoding is...
  31. if line.startswith("Traceback ("):
  32. have_traceback = True
  33. continue
  34. if line.startswith(" "):
  35. continue
  36. if have_traceback:
  37. # first line not starting with a space since the traceback.
  38. # must be the exception!
  39. m = re_exception.match(line)
  40. if m:
  41. exc_type, args = m.groups()
  42. # get hacky - get the *real* exception object from the name.
  43. bits = exc_type.split(".", 1)
  44. if len(bits) > 1:
  45. mod = __import__(bits[0])
  46. exc = getattr(mod, bits[1])
  47. else:
  48. # probably builtin
  49. exc = eval(bits[0])
  50. else:
  51. # hrm - probably just an exception with no args
  52. try:
  53. exc = eval(line.strip())
  54. args = "()"
  55. except:
  56. return None
  57. # try and turn the args into real args.
  58. try:
  59. args = eval(args)
  60. except:
  61. pass
  62. if not isinstance(args, tuple):
  63. args = (args,)
  64. # try and instantiate the exception.
  65. try:
  66. ret = exc(*args)
  67. except:
  68. ret = None
  69. return ret
  70. # apparently not - keep looking...
  71. have_traceback = False
  72. class TestRunner:
  73. def __init__(self, argv):
  74. self.argv = argv
  75. self.__name__ = "Test Runner for cmdline {}".format(argv)
  76. def __call__(self):
  77. import subprocess
  78. p = subprocess.Popen(self.argv,
  79. stdout=subprocess.PIPE,
  80. stderr=subprocess.STDOUT)
  81. output, _ = p.communicate()
  82. rc = p.returncode
  83. if rc:
  84. base = os.path.basename(self.argv[1])
  85. # See if we can detect and reconstruct an exception in the output.
  86. reconstituted = find_exception_in_output(output)
  87. if reconstituted is not None:
  88. raise reconstituted
  89. raise AssertionError("%s failed with exit code %s. Output is:\n%s" % (base, rc, output))
  90. def get_demo_tests():
  91. import win32api
  92. ret = []
  93. demo_dir = os.path.abspath(os.path.join(os.path.dirname(win32api.__file__), "Demos"))
  94. assert os.path.isdir(demo_dir), demo_dir
  95. for name in os.listdir(demo_dir):
  96. base, ext = os.path.splitext(name)
  97. if base in ui_demos and no_user_interaction:
  98. continue
  99. # Skip any other files than .py and bad tests in any case
  100. if ext != ".py" or base in bad_demos:
  101. continue
  102. argv = (sys.executable, os.path.join(demo_dir, base+".py")) + \
  103. argvs.get(base, ())
  104. ret.append(unittest.FunctionTestCase(TestRunner(argv), description="win32/demos/" + name))
  105. return ret
  106. def import_all():
  107. # Some hacks for import order - dde depends on win32ui
  108. try:
  109. import win32ui
  110. except ImportError:
  111. pass # 'what-ev-a....'
  112. import win32api
  113. dir = os.path.dirname(win32api.__file__)
  114. num = 0
  115. is_debug = os.path.basename(win32api.__file__).endswith("_d")
  116. for name in os.listdir(dir):
  117. base, ext = os.path.splitext(name)
  118. if (ext==".pyd") and \
  119. name != "_winxptheme.pyd" and \
  120. (is_debug and base.endswith("_d") or \
  121. not is_debug and not base.endswith("_d")):
  122. try:
  123. __import__(base)
  124. except:
  125. print("FAILED to import", name)
  126. raise
  127. num += 1
  128. def suite():
  129. # Loop over all .py files here, except me :)
  130. try:
  131. me = __file__
  132. except NameError:
  133. me = sys.argv[0]
  134. me = os.path.abspath(me)
  135. files = os.listdir(os.path.dirname(me))
  136. suite = unittest.TestSuite()
  137. suite.addTest(unittest.FunctionTestCase(import_all))
  138. for file in files:
  139. base, ext = os.path.splitext(file)
  140. if ext=='.py' and os.path.basename(me) != file:
  141. try:
  142. mod = __import__(base)
  143. except:
  144. print("FAILED to import test module %r" % base)
  145. traceback.print_exc()
  146. continue
  147. if hasattr(mod, "suite"):
  148. test = mod.suite()
  149. else:
  150. test = unittest.defaultTestLoader.loadTestsFromModule(mod)
  151. suite.addTest(test)
  152. for test in get_demo_tests():
  153. suite.addTest(test)
  154. return suite
  155. class CustomLoader(pywin32_testutil.TestLoader):
  156. def loadTestsFromModule(self, module):
  157. return self.fixupTestsForLeakTests(suite())
  158. if __name__ == '__main__':
  159. import argparse
  160. parser = argparse.ArgumentParser(description="Test runner for PyWin32/win32")
  161. parser.add_argument("-no-user-interaction",
  162. default=no_user_interaction,
  163. action='store_true',
  164. help="Run all tests without user interaction")
  165. parsed_args, remains = parser.parse_known_args()
  166. no_user_interaction = parsed_args.no_user_interaction
  167. sys.argv = [sys.argv[0]] + remains
  168. pywin32_testutil.testmain(testLoader=CustomLoader())