Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

util.py 8.0KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import gc
  2. import logging
  3. import os
  4. import sys
  5. import tempfile
  6. import unittest
  7. import winreg
  8. import pythoncom
  9. import pywin32_testutil
  10. import pywintypes
  11. import win32api
  12. import win32com
  13. import winerror
  14. from pythoncom import _GetGatewayCount, _GetInterfaceCount
  15. from pywin32_testutil import LeakTestCase, TestLoader, TestResult, TestRunner
  16. def CheckClean():
  17. # Ensure no lingering exceptions - Python should have zero outstanding
  18. # COM objects
  19. try:
  20. sys.exc_clear()
  21. except AttributeError:
  22. pass # py3k
  23. c = _GetInterfaceCount()
  24. if c:
  25. print("Warning - %d com interface objects still alive" % c)
  26. c = _GetGatewayCount()
  27. if c:
  28. print("Warning - %d com gateway objects still alive" % c)
  29. def RegisterPythonServer(filename, progids=None, verbose=0):
  30. if progids:
  31. if isinstance(progids, str):
  32. progids = [progids]
  33. # we know the CLSIDs we need, but we might not be an admin user
  34. # and otherwise unable to register them. So as long as the progids
  35. # exist and the DLL points at our version, assume it already is.
  36. why_not = None
  37. for progid in progids:
  38. try:
  39. clsid = pywintypes.IID(progid)
  40. except pythoncom.com_error:
  41. # not registered.
  42. break
  43. try:
  44. HKCR = winreg.HKEY_CLASSES_ROOT
  45. hk = winreg.OpenKey(HKCR, "CLSID\\%s" % clsid)
  46. dll = winreg.QueryValue(hk, "InprocServer32")
  47. except WindowsError:
  48. # no CLSID or InProcServer32 - not registered
  49. break
  50. ok_files = [
  51. os.path.basename(pythoncom.__file__),
  52. "pythoncomloader%d%d.dll" % (sys.version_info[0], sys.version_info[1]),
  53. ]
  54. if os.path.basename(dll) not in ok_files:
  55. why_not = "%r is registered against a different Python version (%s)" % (
  56. progid,
  57. dll,
  58. )
  59. break
  60. else:
  61. # print "Skipping registration of '%s' - already registered" % filename
  62. return
  63. # needs registration - see if its likely!
  64. try:
  65. from win32com.shell.shell import IsUserAnAdmin
  66. except ImportError:
  67. print("Can't import win32com.shell - no idea if you are an admin or not?")
  68. is_admin = False
  69. else:
  70. try:
  71. is_admin = IsUserAnAdmin()
  72. except pythoncom.com_error:
  73. # old, less-secure OS - assume *is* admin.
  74. is_admin = True
  75. if not is_admin:
  76. msg = (
  77. "%r isn't registered, but I'm not an administrator who can register it."
  78. % progids[0]
  79. )
  80. if why_not:
  81. msg += "\n(registration check failed as %s)" % why_not
  82. # throw a normal "class not registered" exception - we don't report
  83. # them the same way as "real" errors.
  84. raise pythoncom.com_error(winerror.CO_E_CLASSSTRING, msg, None, -1)
  85. # so theoretically we are able to register it.
  86. cmd = '%s "%s" --unattended > nul 2>&1' % (win32api.GetModuleFileName(0), filename)
  87. if verbose:
  88. print("Registering engine", filename)
  89. # print cmd
  90. rc = os.system(cmd)
  91. if rc:
  92. print("Registration command was:")
  93. print(cmd)
  94. raise RuntimeError("Registration of engine '%s' failed" % filename)
  95. def ExecuteShellCommand(
  96. cmd,
  97. testcase,
  98. expected_output=None, # Set to '' to check for nothing
  99. tracebacks_ok=0, # OK if the output contains a t/b?
  100. ):
  101. output_name = tempfile.mktemp("win32com_test")
  102. cmd = cmd + ' > "%s" 2>&1' % output_name
  103. rc = os.system(cmd)
  104. output = open(output_name, "r").read().strip()
  105. os.remove(output_name)
  106. class Failed(Exception):
  107. pass
  108. try:
  109. if rc:
  110. raise Failed("exit code was " + str(rc))
  111. if expected_output is not None and output != expected_output:
  112. raise Failed("Expected output %r (got %r)" % (expected_output, output))
  113. if not tracebacks_ok and output.find("Traceback (most recent call last)") >= 0:
  114. raise Failed("traceback in program output")
  115. return output
  116. except Failed as why:
  117. print("Failed to exec command '%r'" % cmd)
  118. print("Failed as", why)
  119. print("** start of program output **")
  120. print(output)
  121. print("** end of program output **")
  122. testcase.fail("Executing '%s' failed as %s" % (cmd, why))
  123. def assertRaisesCOM_HRESULT(testcase, hresult, func, *args, **kw):
  124. try:
  125. func(*args, **kw)
  126. except pythoncom.com_error as details:
  127. if details.hresult == hresult:
  128. return
  129. testcase.fail("Excepected COM exception with HRESULT 0x%x" % hresult)
  130. class CaptureWriter:
  131. def __init__(self):
  132. self.old_err = self.old_out = None
  133. self.clear()
  134. def capture(self):
  135. self.clear()
  136. self.old_out = sys.stdout
  137. self.old_err = sys.stderr
  138. sys.stdout = sys.stderr = self
  139. def release(self):
  140. if self.old_out:
  141. sys.stdout = self.old_out
  142. self.old_out = None
  143. if self.old_err:
  144. sys.stderr = self.old_err
  145. self.old_err = None
  146. def clear(self):
  147. self.captured = []
  148. def write(self, msg):
  149. self.captured.append(msg)
  150. def get_captured(self):
  151. return "".join(self.captured)
  152. def get_num_lines_captured(self):
  153. return len("".join(self.captured).split("\n"))
  154. # Utilities to set the win32com logger to something what just captures
  155. # records written and doesn't print them.
  156. class LogHandler(logging.Handler):
  157. def __init__(self):
  158. self.emitted = []
  159. logging.Handler.__init__(self)
  160. def emit(self, record):
  161. self.emitted.append(record)
  162. _win32com_logger = None
  163. def setup_test_logger():
  164. old_log = getattr(win32com, "logger", None)
  165. global _win32com_logger
  166. if _win32com_logger is None:
  167. _win32com_logger = logging.Logger("test")
  168. handler = LogHandler()
  169. _win32com_logger.addHandler(handler)
  170. win32com.logger = _win32com_logger
  171. handler = _win32com_logger.handlers[0]
  172. handler.emitted = []
  173. return handler.emitted, old_log
  174. def restore_test_logger(prev_logger):
  175. assert prev_logger is None, "who needs this?"
  176. if prev_logger is None:
  177. del win32com.logger
  178. else:
  179. win32com.logger = prev_logger
  180. # We used to override some of this (and may later!)
  181. TestCase = unittest.TestCase
  182. def CapturingFunctionTestCase(*args, **kw):
  183. real_test = _CapturingFunctionTestCase(*args, **kw)
  184. return LeakTestCase(real_test)
  185. class _CapturingFunctionTestCase(unittest.FunctionTestCase): # , TestCaseMixin):
  186. def __call__(self, result=None):
  187. if result is None:
  188. result = self.defaultTestResult()
  189. writer = CaptureWriter()
  190. # self._preTest()
  191. writer.capture()
  192. try:
  193. unittest.FunctionTestCase.__call__(self, result)
  194. if getattr(self, "do_leak_tests", 0) and hasattr(sys, "gettotalrefcount"):
  195. self.run_leak_tests(result)
  196. finally:
  197. writer.release()
  198. # self._postTest(result)
  199. output = writer.get_captured()
  200. self.checkOutput(output, result)
  201. if result.showAll:
  202. print(output)
  203. def checkOutput(self, output, result):
  204. if output.find("Traceback") >= 0:
  205. msg = "Test output contained a traceback\n---\n%s\n---" % output
  206. result.errors.append((self, msg))
  207. class ShellTestCase(unittest.TestCase):
  208. def __init__(self, cmd, expected_output):
  209. self.__cmd = cmd
  210. self.__eo = expected_output
  211. unittest.TestCase.__init__(self)
  212. def runTest(self):
  213. ExecuteShellCommand(self.__cmd, self, self.__eo)
  214. def __str__(self):
  215. max = 30
  216. if len(self.__cmd) > max:
  217. cmd_repr = self.__cmd[:max] + "..."
  218. else:
  219. cmd_repr = self.__cmd
  220. return "exec: " + cmd_repr
  221. def testmain(*args, **kw):
  222. pywin32_testutil.testmain(*args, **kw)
  223. CheckClean()