util.py 7.8 KB

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