[ctypes-commit] ctypes/win32/com/test test_word.py,NONE,1.1.2.1 test_variant.py,NONE,1.1.2.1 test_sy
Brought to you by:
theller
From: Thomas H. <th...@us...> - 2005-11-04 07:44:52
|
Update of /cvsroot/ctypes/ctypes/win32/com/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12281 Added Files: Tag: branch_1_0 test_word.py test_variant.py test_sysalloc.py test_safearray.py test_perf.py test_comobject.py __init__.py .cvsignore Log Message: Move ctypes.com tests into the ctypes.com.test package. --- NEW FILE: .cvsignore --- *.pyc *.pyo --- NEW FILE: test_comobject.py --- import unittest, os, sys from ctypes import * def get_refcnt(comptr): if not comptr: return 0 comptr.AddRef() return comptr.Release() class Test_EmptyComPointer(unittest.TestCase): # This test makes sure that calling a COM method on a COM # interface pointer raises a ValueError, when the interface # pointer points to NULL. def setUp(self): from ctypes.com import IUnknown self._orig_del = POINTER(IUnknown).__del__ # We replace the __del__ method (which calls self.Release(), # because it would crash. def __del__(self): pass POINTER(IUnknown).__del__ = __del__ def tearDown(self): from ctypes.com import IUnknown POINTER(IUnknown).__del__ = self._orig_del def test_comcrash(self): from ctypes.com import IUnknown p = pointer(IUnknown()) try: p.AddRef() except ValueError, message: self.failUnlessEqual(str(message), "COM method call without VTable") else: self.fail("Exception expected") class ComTestCase(unittest.TestCase): def __init__(self, *args): unittest.TestCase.__init__(self, *args) global COMObject, IUnknown, GUID, STDMETHOD, HRESULT from ctypes.com import COMObject, IUnknown, GUID, STDMETHOD, HRESULT def setUp(self): class IObjectWithSite(IUnknown): _iid_ = GUID("{FC4801A3-2BA9-11CF-A229-00AA003D7352}") _methods_ = IUnknown._methods_ + [ (STDMETHOD(HRESULT, "SetSite", POINTER(IUnknown))), (STDMETHOD(HRESULT, "GetSite", POINTER(GUID), POINTER(c_void_p)))] class Factory(object): def LockServer(self, *args): pass class MyObject(COMObject): _factory = Factory() _com_interfaces_ = [IObjectWithSite] def IObjectWithSite_SetSite(self, this, pUnkSite): self.m_site = pUnkSite return 0 # S_OK self.impl = MyObject() def tearDown(self): self.impl = None import gc gc.collect() ################ def test_site(self): impl = self.impl p = pointer(impl._com_pointers_[0][1]) self.failUnlessEqual(impl._refcnt, 0) p.AddRef() self.failUnlessEqual(impl._refcnt, 1) p.SetSite(p) self.failUnlessEqual(impl._refcnt, 2) p.SetSite(None) self.failUnlessEqual(impl._refcnt, 1) del p self.failUnlessEqual(impl._refcnt, 0) def test_comobject(self): impl = self.impl self.failUnlessEqual(impl._refcnt, 0) p = pointer(impl._com_pointers_[0][1]) p.AddRef() self.failUnlessEqual(impl._refcnt, 1) self.failUnlessEqual(get_refcnt(p), 1) del p self.failUnlessEqual(impl._refcnt, 0) def test_qi(self): impl = self.impl self.failUnlessEqual(impl._refcnt, 0) p = pointer(impl._com_pointers_[0][1]) p.AddRef() self.failUnlessEqual(get_refcnt(p), 1) p2 = POINTER(IUnknown)() p.QueryInterface(byref(IUnknown._iid_), byref(p2)) self.failUnlessEqual(get_refcnt(p), 2) del p2 self.failUnlessEqual(get_refcnt(p), 1) def test_from_progid(self): g = GUID.from_progid("InternetExplorer.Application") self.failUnlessEqual(g, GUID("{0002DF01-0000-0000-C000-000000000046}")) def test_GUID(self): g1 = GUID("{00000000-0001-0002-0003-000000000000}") g2 = GUID("{00000000-0001-0002-0003-000000000000}") g3 = GUID("{00000000-0001-0002-0003-000000000001}") self.failUnlessEqual(g1, g2) # for now, GUID instances are unhashable. ## d = {} ## d[g1] = None ## self.failUnlessEqual(g1 in d, True) ## self.failUnlessEqual(g2 in d, True) ## self.failUnlessEqual(g3 in d, False) ################################################################ if __name__ == '__main__': unittest.main() --- NEW FILE: test_perf.py --- import sys, re # Some preformance measurements def timeit(*args): from timeit import main from cStringIO import StringIO prev_stdout = sys.stdout sys.stdout = StringIO() main(args) out = sys.stdout.getvalue() sys.stdout = prev_stdout match = re.search(r"(\d+\.\d*|\d+) usec", out) time = float(match.group(1)) print "%8.2f: %s" % (time, args[-1]) ################################################################ import ctypes from ctypes import * class POINT(Structure): _fields_ = [("x", c_int), ("y", c_int)] class RECT(Structure): _fields_ = [("ul", POINT), ("lr", POINT)] class Class(object): pass def get_fd(): # get a FUNCDESC instance from a typelib from comtypes.typeinfo import LoadTypeLibEx from comtypes import GUID tlib = LoadTypeLibEx("shdocvw.dll") # IWebBrowser interface tinfo = tlib.GetTypeInfoOfGuid(GUID("{EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B}")) tcomp = tinfo.GetTypeComp() kind, fd = tcomp.Bind("Navigate") return fd ################################################################ if __name__ == "__main__": print "ctypes version:", ctypes.__version__ print "python version:", sys.version timeit("-s", "from test_perf import Class", "Class()") timeit("-s", "from test_perf import POINT", "POINT()") timeit("-s", "from test_perf import RECT", "RECT()") timeit("-s", "from test_perf import POINT; point = POINT()", "point.y") timeit("-s", "from test_perf import RECT; rect = RECT()", "rect.lr") timeit("-s", "from test_perf import get_fd; fd = get_fd()", "fd.lprgelemdescParam") timeit("-s", "from test_perf import get_fd; fd = get_fd()", "fd.lprgelemdescParam[0]") timeit("-s", "from test_perf import get_fd; fd = get_fd()", "fd.lprgelemdescParam[1]") timeit("-s", "from test_perf import get_fd; fd = get_fd()", "fd.lprgelemdescParam[1].tdesc") timeit("-s", "from test_perf import get_fd; fd = get_fd()", "fd.lprgelemdescParam[1].tdesc.vt") timeit("-s", "from test_perf import get_fd; fd = get_fd()", "fd.lprgelemdescParam[1].tdesc._.lptdesc[0].vt") timeit('-s', "from ctypes import c_int", "c_int()") timeit('-s', "from ctypes import c_int", "c_int(42)") timeit('-s', "from ctypes.com.automation import VARIANT", "VARIANT() # ctypes.com") timeit('-s', "from ctypes.com.automation import VARIANT; variant = VARIANT(3)", "variant.value # ctypes.com") timeit('-s', "from ctypes.com.automation import VARIANT; variant = VARIANT()", "variant.value = 3.14 # ctypes.com") try: import comtypes except ImportError: pass else: timeit('-s', "from comtypes.automation import VARIANT", "VARIANT() # comtypes") timeit('-s', "from comtypes.automation import VARIANT; variant = VARIANT(3)", "variant.value # comtypes") timeit('-s', "from comtypes.automation import VARIANT; variant = VARIANT()", "variant.value = 3.14 # comtypes") timeit('-s', "from comtypes.automation import VARIANT; variant = VARIANT()", "variant.value = (3.14, None, u'foo') # comtypes") timeit('-s', "from comtypes.automation import VARIANT; variant = VARIANT((3.14, None, 'foo'))", "variant.value # comtypes") # on my machine which has around 30000 pystones/second: ##ctypes version: 0.9.2 ##python version: 2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bit (Intel)] ## 0.38: Class() ## 1.97: POINT() ## 1.98: RECT() ## 0.24: point.y ## 2.43: rect.lr ## 7.21: fd.lprgelemdescParam ## 10.90: fd.lprgelemdescParam[0] ## 12.00: fd.lprgelemdescParam[1] ## 15.30: fd.lprgelemdescParam[1].tdesc ## 16.00: fd.lprgelemdescParam[1].tdesc.vt ## 26.20: fd.lprgelemdescParam[1].tdesc.u.lptdesc[0].vt ## 1.80: c_int() ## 1.97: c_int(42) ## 2.93: VARIANT() # ctypes.com ## 5.30: variant.value # ctypes.com ## 11.60: variant.value = 3.14 # ctypes.com ##ctypes version: 0.9.3 ##python version: 2.4 (#60, Nov 30 2004, 11:49:19) [MSC v.1310 32 bit (Intel)] ## 0.37: Class() ## 0.96: POINT() ## 0.94: RECT() ## 0.25: point.y ## 1.94: rect.lr ## 7.16: fd.lprgelemdescParam ## 10.10: fd.lprgelemdescParam[0] ## 10.00: fd.lprgelemdescParam[1] ## 12.30: fd.lprgelemdescParam[1].tdesc ## 13.70: fd.lprgelemdescParam[1].tdesc.vt ## 19.30: fd.lprgelemdescParam[1].tdesc.u.lptdesc[0].vt ## 1.16: c_int() ## 1.34: c_int(42) ## 2.40: VARIANT() # ctypes.com ## 5.25: variant.value # ctypes.com ## 11.20: variant.value = 3.14 # ctypes.com ## 2.08: VARIANT() # comtypes ## 4.99: variant.value # comtypes ## 11.40: variant.value = 3.14 # comtypes ##ctypes version: 0.9.8 (not yet released, 2005/05/11) ##python version: 2.4.1 (#65, Mar 30 2005, 09:13:57) [MSC v.1310 32 bit (Intel)] ## 0.41: Class() ## 0.48: POINT() ## 0.48: RECT() ## 0.26: point.y ## 0.56: rect.lr ## 0.61: fd.lprgelemdescParam ## 1.14: fd.lprgelemdescParam[0] ## 1.20: fd.lprgelemdescParam[1] ## 1.76: fd.lprgelemdescParam[1].tdesc ## 1.93: fd.lprgelemdescParam[1].tdesc.vt ## 3.60: fd.lprgelemdescParam[1].tdesc._.lptdesc[0].vt ## 0.48: c_int() ## 0.72: c_int(42) ## 1.75: VARIANT() # ctypes.com ## 3.21: variant.value # ctypes.com ## 8.23: variant.value = 3.14 # ctypes.com ## 1.46: VARIANT() # comtypes ## 3.11: variant.value # comtypes ## 8.57: variant.value = 3.14 # comtypes ##ctypes version: 0.9.8 (not yet released, 2005/05/12) ##python version: 2.4.1 (#65, Mar 30 2005, 09:13:57) [MSC v.1310 32 bit (Intel)] ## 0.40: Class() ## 0.47: POINT() ## 0.48: RECT() ## 0.25: point.y ## 0.49: rect.lr ## 0.49: fd.lprgelemdescParam ## 0.96: fd.lprgelemdescParam[0] ## 0.99: fd.lprgelemdescParam[1] ## 1.48: fd.lprgelemdescParam[1].tdesc ## 1.63: fd.lprgelemdescParam[1].tdesc.vt ## 3.02: fd.lprgelemdescParam[1].tdesc._.lptdesc[0].vt ## 0.48: c_int() ## 0.71: c_int(42) ## 1.75: VARIANT() # ctypes.com ## 3.17: variant.value # ctypes.com ## 8.07: variant.value = 3.14 # ctypes.com ## 1.51: VARIANT() # comtypes ## 3.12: variant.value # comtypes ## 8.75: variant.value = 3.14 # comtypes --- NEW FILE: __init__.py --- # --- NEW FILE: test_word.py --- from ctypes.com import hresult from ctypes.com.client import Dispatch from ctypes.test import requires requires("ui") import unittest class Word(unittest.TestCase): def test_word(self): try: word = Dispatch("Word.Application") except WindowsError, details: if details.errno == hresult.CO_E_CLASSSTRING: self.fail("It seems Word is not installed...") raise word.Visible = 1 doc = word.Documents.Add() wrange = doc.Range() for i in range(10): wrange.InsertAfter("Hello from ctypes via COM %d\n" % i) paras = doc.Paragraphs for i in range(len(paras)): p = paras[i]() p.Font.ColorIndex = i+1 p.Font.Size = 12 + (2 * i) doc.Close(SaveChanges=0) word.Quit() if __name__ == '__main__': unittest.main() --- NEW FILE: test_sysalloc.py --- import unittest from ctypes import * from ctypes.com import mallocspy, ole32 from ctypes.com.automation import BSTR, VARIANT import _ctypes_test class MallocSpyTest(unittest.TestCase): def setUp(self): # ctypes.com has called CoInitialize, but we must install the spy # in uninitialized state. ole32.CoUninitialize() self.expect = None self.mallocspy = mallocspy.MallocSpy() self.mallocspy.register() ole32.CoInitialize(None) def tearDown(self): try: try: # Even if tests fail or crash, we have to make sure we can # shutdown safely. The problem is that mallocspy cannot be # revoked completely while there are still unfreed memory # blocks which have been allocated while it was registered. # # So, we must delete *all* COM objects we still have anywhere, # even if an error occurred somewhere, and then shutdown COM, # BEFORE Python exits. try: 1/0 except: pass ole32.CoUninitialize() # Now, check the desired test outcome: self.failUnlessEqual(len(self.mallocspy.active_blocks()), self.expect) finally: self.mallocspy.revoke(warn=0) finally: # we must restore the environment to the state we found it! ole32.CoInitialize(None) ################ def test_leak(self): # Allocate 10 BSTR's without freeing them, and make sure the # leak is detected for i in range(10): windll.oleaut32.SysAllocString(unicode("Python is cool %s" % i)) self.expect = 10 def test_no_leak(self): # Allocate 10 BSTR's then free them, and make sure *no* leak # is detected L = [] for i in range(10): b = windll.oleaut32.SysAllocString(unicode("Python is cool %s" % i)) L.append(b) for b in L: windll.oleaut32.SysFreeString(b) self.expect = 0 def test_GetString_C(self): # GetString is this function, implemented in C: # # EXPORT(void) GetString(BSTR *pbstr) # { # *pbstr = SysAllocString(L"Goodbye!"); # } GetString = CDLL(_ctypes_test.__file__).GetString # XXX Explain why we cannot create b outside the loop! # And why we cannot do anything against this :-) for i in range(32): b = BSTR() GetString(byref(b)) self.expect = 0 def test_GetString_Python(self): # Same test as before, but with ctypes implemented C function PROTO = WINFUNCTYPE(None, POINTER(BSTR), c_int) def func(pbstr, i): pbstr[0] = "%s %s" % ("Spam, spam, and spam", i) func = PROTO(func) for i in range(32): b = BSTR() func(byref(b), i) self.failUnlessEqual(b.value, "%s %s" % ("Spam, spam, and spam", i)) self.expect = 0 def test_BSTR_alloc(self): for i in range(32): BSTR(u"Hello World %d" % i) self.expect = 0 def test_BSTR_pointer(self): for i in range(32): p = pointer(BSTR()) p.value = u"Hello World %d" % i self.expect = 0 def test_VARIANT(self): # We still have to clear variants manually, to avoid memory leaks. for i in range(32): v = VARIANT("Hello, World") v.value = None self.expect = 0 def test_VARIANT_memleak(self): # This demonstrates the memory leak: for i in range(32): VARIANT("Hello, World") self.expect = 32 # Offtopic for this test: # XXX These need better error messages: ## POINTER(BSTR()) # TypeError: unhashable type ## pointer(BSTR) # TypeError: _type_ must have storage info ################################################################ if __name__ == "__main__": unittest.main() --- NEW FILE: test_safearray.py --- import unittest, os from ctypes import * from ctypes.com import IUnknown, GUID from ctypes.com.automation import VARIANT, LoadTypeLibEx, \ VT_ARRAY, VT_VARIANT, VT_I4, VT_INT, oleaut32, IDispatch # test VT_ARRAY in VARIANTS class SAFEARRAYTest(unittest.TestCase): def test_VT_VARIANT(self): v = VARIANT() # lists... v.value = [1, "spam", [None, "foo"]] self.failUnlessEqual(v.value, [1, "spam", [None, "foo"]]) self.failUnlessEqual(v.vt, VT_VARIANT | VT_ARRAY) dim = oleaut32.SafeArrayGetDim(v._.voidp) self.failUnlessEqual(dim, 1) # and tuples. v.value = (1, "spam", (None, "foo")) self.failUnlessEqual(v.value, [1, "spam", [None, "foo"]]) def test_VT_INT(self): import array data = array.array("i", (1, 2, 3, 4, 5)) v = VARIANT() v.value = data self.failUnlessEqual(v.vt, VT_INT | VT_ARRAY) dim = oleaut32.SafeArrayGetDim(v._.voidp) self.failUnlessEqual(dim, 1) def _getrefcnt(self, comobj): comobj.AddRef() return comobj.Release() def test_VT_UNKNOWN(self): tlb = LoadTypeLibEx(r"c:\windows\system32\shdocvw.dll") self.failUnlessEqual(self._getrefcnt(tlb), 1) v = VARIANT() v.value = tlb self.failUnlessEqual(self._getrefcnt(tlb), 2) v.value = None self.failUnlessEqual(self._getrefcnt(tlb), 1) v.value = [tlb] self.failUnlessEqual(self._getrefcnt(tlb), 2) pcom = v.value[0] self.failUnlessEqual(self._getrefcnt(tlb), 3) self.failUnlessEqual(self._getrefcnt(pcom), 3) # ITypeLib derives from IUnknown, and VARIANT can only store IUnknown or IDispatch # pointers, so: self.failUnlessEqual(type(pcom), POINTER(IUnknown)) del pcom self.failUnlessEqual(self._getrefcnt(tlb), 2) v.value = None self.failUnlessEqual(self._getrefcnt(tlb), 1) def test_VT_DISPATCH(self): from ctypes.com.client import Dispatch p = Dispatch("MSScriptControl.ScriptControl") # any inproc IDispatch will do pdisp = p._comobj self.failUnlessEqual(self._getrefcnt(pdisp), 1) v = VARIANT() v.value = pdisp self.failUnlessEqual(self._getrefcnt(pdisp), 2) v.value = None self.failUnlessEqual(self._getrefcnt(pdisp), 1) v.value = [pdisp] self.failUnlessEqual(self._getrefcnt(pdisp), 2) pcom = v.value[0] self.failUnlessEqual(self._getrefcnt(pdisp), 3) self.failUnlessEqual(self._getrefcnt(pcom), 3) # ITypeLib derives from IUnknown, and VARIANT can only store IUnknown or IDispatch # pointers, so: self.failUnlessEqual(type(pcom), POINTER(IDispatch)) del pcom self.failUnlessEqual(self._getrefcnt(pdisp), 2) v.value = None self.failUnlessEqual(self._getrefcnt(pdisp), 1) ## def test_multidim() if __name__ == "__main__": unittest.main() --- NEW FILE: test_variant.py --- import unittest, os from ctypes import * from ctypes.com import IUnknown, GUID from ctypes.com.automation import VARIANT, LoadTypeLibEx, DISPPARAMS, LoadRegTypeLib def get_refcnt(comptr): # return the COM reference count of a COM interface pointer if not comptr: return 0 comptr.AddRef() return comptr.Release() class VariantTestCase(unittest.TestCase): def test_com_refcounts(self): # typelib for Internet Explorer tlb = LoadRegTypeLib(GUID("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}"), 1, 1, 0) self.failUnlessEqual(get_refcnt(tlb), 1) p = POINTER(IUnknown)() tlb.QueryInterface(byref(IUnknown._iid_), byref(p)) self.failUnlessEqual(get_refcnt(tlb), 2) del p self.failUnlessEqual(get_refcnt(tlb), 1) def test_com_pointers(self): # Storing a COM interface pointer in a VARIANT increments the refcount, # changing the variant to contain something else decrements it tlb = LoadRegTypeLib(GUID("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}"), 1, 1, 0) self.failUnlessEqual(get_refcnt(tlb), 1) v = VARIANT(tlb) self.failUnlessEqual(get_refcnt(tlb), 2) p = v.value self.failUnlessEqual(get_refcnt(tlb), 3) del p self.failUnlessEqual(get_refcnt(tlb), 2) v.value = None self.failUnlessEqual(get_refcnt(tlb), 1) def test_null_com_pointers(self): p = POINTER(IUnknown)() self.failUnlessEqual(get_refcnt(p), 0) v = VARIANT(p) self.failUnlessEqual(get_refcnt(p), 0) def test_dispparams(self): # DISPPARAMS is a complex structure, well worth testing. d = DISPPARAMS() d.rgvarg = (VARIANT * 3)() # XXX The following line fails, which is a real bug in ctypes: # SystemError: ...\Objects\listobject.c:105: bad argument to internal function # # Update: this bug is fixed, now I have to rememeber what I wanted to test here. d.rgvarg[0].value = 1 def test_pythonobjects(self): objects = [None, 42, 3.14, True, False, "abc", u"abc", 7L] for x in objects: v = VARIANT(x) self.failUnlessEqual(x, v.value) def test_integers(self): import sys v = VARIANT() v.value = sys.maxint self.failUnlessEqual(v.value, sys.maxint) self.failUnlessEqual(type(v.value), int) v.value += 1 self.failUnlessEqual(v.value, sys.maxint+1) self.failUnlessEqual(type(v.value), float) v.value = 1L self.failUnlessEqual(v.value, 1) self.failUnlessEqual(type(v.value), int) def test_datetime(self): import datetime now = datetime.datetime.now() v = VARIANT() v.value = now from ctypes.com.automation import VT_DATE self.failUnlessEqual(v.vt, VT_DATE) self.failUnlessEqual(v.value, now) def test_BSTR(self): from ctypes.com.automation import BSTR, VT_BSTR v = VARIANT() v.value = u"abc\x00123\x00" self.failUnlessEqual(v.value, "abc\x00123\x00") v.value = None # manually clear the variant v._.VT_I4 = 0 # NULL pointer BSTR should be handled as empty string v.vt = VT_BSTR self.failUnlessEqual(v.value, "") class ArrayTest(unittest.TestCase): def test_double(self): import array for typecode in "df": # because of FLOAT rounding errors, whi will only work for # certain values! a = array.array(typecode, [1.0, 2.0, 3.0, 4.5]) v = VARIANT() v.value = a self.failUnlessEqual(v.value, [1.0, 2.0, 3.0, 4.5]) def test_int(self): import array for typecode in "bhiBHIlL": a = array.array(typecode, [1, 1, 1, 1]) v = VARIANT() v.value = a self.failUnlessEqual(v.value, [1, 1, 1, 1]) ################################################################ if __name__ == '__main__': unittest.main() |