0001 # Test code for a VB Program. 0002 # 0003 # This requires the PythonCOM VB Test Harness. 0004 # 0005 0006 import winerror 0007 import pythoncom, win32com.client, win32com.client.dynamic, win32com.client.gencache 0008 from win32com.server.util import NewCollection, wrap 0009 import string 0010 import util 0011 0012 importMsg = """\ 0013 **** VB Test harness is not installed *** 0014 This test requires a VB test program to be built and installed 0015 on this PC. 0016 """ 0017 0018 ### NOTE: VB SUCKS! 0019 ### If you delete the DLL built by VB, then reopen VB 0020 ### to rebuild the DLL, it loses the IID of the object!!! 0021 ### So I will try to avoid this in the future :-) 0022 0023 # Import the type library for the test module. 0024 try: 0025 win32com.client.gencache.EnsureDispatch("PyCOMVBTest.Tester") 0026 except pythoncom.com_error: 0027 raise RuntimeError, importMsg 0028 0029 import traceback 0030 0031 # for debugging 0032 useDispatcher = None 0033 ## import win32com.server.dispatcher 0034 ## useDispatcher = win32com.server.dispatcher.DefaultDebugDispatcher 0035 0036 error = "VB Test Error" 0037 0038 # Set up a COM object that VB will do some callbacks on. This is used 0039 # to test byref params for gateway IDispatch. 0040 class TestObject: 0041 _public_methods_ = ["CallbackVoidOneByRef","CallbackResultOneByRef", "CallbackVoidTwoByRef", 0042 "CallbackString","CallbackResultOneByRefButReturnNone", 0043 "CallbackVoidOneByRefButReturnNone", 0044 "CallbackArrayResult", "CallbackArrayResultOneArrayByRef", 0045 "CallbackArrayResultWrongSize" 0046 ] 0047 def CallbackVoidOneByRef(self, intVal): 0048 return intVal + 1 0049 def CallbackResultOneByRef(self, intVal): 0050 return intVal, intVal + 1 0051 def CallbackVoidTwoByRef(self, int1, int2): 0052 return int1+int2, int1-int2 0053 def CallbackString(self, strVal): 0054 return 0, strVal + " has visited Python" 0055 def CallbackArrayResult(self, arrayVal): 0056 ret = [] 0057 for i in arrayVal: 0058 ret.append(i+1) 0059 # returning as a list forces it be processed as a single result 0060 # (rather than a tuple, where it may be interpreted as 0061 # multiple results for byref unpacking) 0062 return ret 0063 def CallbackArrayResultWrongSize(self, arrayVal): 0064 return list(arrayVal[:-1]) 0065 def CallbackArrayResultOneArrayByRef(self, arrayVal): 0066 ret = [] 0067 for i in arrayVal: 0068 ret.append(i+1) 0069 # See above for list processing. 0070 return list(arrayVal), ret 0071 0072 def CallbackResultOneByRefButReturnNone(self, intVal): 0073 return 0074 def CallbackVoidOneByRefButReturnNone(self, intVal): 0075 return 0076 0077 def TestVB( vbtest, bUseGenerated ): 0078 vbtest.LongProperty = -1 0079 if vbtest.LongProperty != -1: 0080 raise error, "Could not set the long property correctly." 0081 vbtest.IntProperty = 10 0082 if vbtest.IntProperty != 10: 0083 raise error, "Could not set the integer property correctly." 0084 vbtest.VariantProperty = 10 0085 if vbtest.VariantProperty != 10: 0086 raise error, "Could not set the variant integer property correctly." 0087 vbtest.StringProperty = "Hello from Python" 0088 if vbtest.StringProperty != "Hello from Python": 0089 raise error, "Could not set the string property correctly." 0090 vbtest.VariantProperty = "Hello from Python" 0091 if vbtest.VariantProperty != "Hello from Python": 0092 raise error, "Could not set the variant string property correctly." 0093 vbtest.VariantProperty = (1.0, 2.0, 3.0) 0094 if vbtest.VariantProperty != (1.0, 2.0, 3.0): 0095 raise error, "Could not set the variant property to an array of floats correctly - '%s'." % (vbtest.VariantProperty,) 0096 0097 TestArrays(vbtest, bUseGenerated) 0098 TestStructs(vbtest) 0099 TestCollections(vbtest) 0100 0101 assert vbtest.TakeByValObject(vbtest)==vbtest 0102 0103 # Python doesnt support PUTREF properties without a typeref 0104 # (although we could) 0105 if bUseGenerated: 0106 ob = vbtest.TakeByRefObject(vbtest) 0107 assert ob[0]==vbtest and ob[1]==vbtest 0108 0109 # A property that only has PUTREF defined. 0110 vbtest.VariantPutref = vbtest 0111 if vbtest.VariantPutref._oleobj_!= vbtest._oleobj_: 0112 raise error, "Could not set the VariantPutref property correctly." 0113 # Cant test further types for this VariantPutref, as only 0114 # COM objects can be stored ByRef. 0115 0116 # A "set" type property - only works for generated. 0117 # VB recognizes a collection via a few "private" interfaces that we 0118 # could later build support in for. 0119 # vbtest.CollectionProperty = NewCollection((1,2,"3", "Four")) 0120 # if vbtest.CollectionProperty != (1,2,"3", "Four"): 0121 # raise error, "Could not set the Collection property correctly - got back " + str(vbtest.CollectionProperty) 0122 0123 # These are sub's that have a single byref param 0124 # Result should be just the byref. 0125 if vbtest.IncrementIntegerParam(1) != 2: 0126 raise error, "Could not pass an integer byref" 0127 0128 # Sigh - we cant have *both* "ommited byref" and optional args 0129 # We really have to opt that args nominated as optional work as optional 0130 # rather than simply all byrefs working as optional. 0131 # if vbtest.IncrementIntegerParam() != 1: 0132 # raise error, "Could not pass an omitted integer byref" 0133 0134 if vbtest.IncrementVariantParam(1) != 2: 0135 raise error, "Could not pass an int VARIANT byref:"+str(vbtest.IncrementVariantParam(1)) 0136 0137 if vbtest.IncrementVariantParam(1.5) != 2.5: 0138 raise error, "Could not pass a float VARIANT byref" 0139 0140 # Can't test IncrementVariantParam with the param omitted as it 0141 # it not declared in the VB code as "Optional" 0142 callback_ob = wrap(TestObject(), useDispatcher = useDispatcher) 0143 vbtest.DoSomeCallbacks(callback_ob) 0144 0145 ret = vbtest.PassIntByVal(1) 0146 if ret != 2: 0147 raise error, "Could not increment the integer - "+str(ret) 0148 0149 TestVBInterface(vbtest) 0150 # Python doesnt support byrefs without some sort of generated support. 0151 if bUseGenerated: 0152 # This is a VB function that takes a single byref 0153 # Hence 2 return values - function and byref. 0154 ret = vbtest.PassIntByRef(1) 0155 if ret != (1,2): 0156 raise error, "Could not increment the integer - "+str(ret) 0157 # Check you can leave a byref arg blank. 0158 # see above 0159 # ret = vbtest.PassIntByRef() 0160 # if ret != (0,1): 0161 # raise error, "Could not increment the integer with default arg- "+str(ret) 0162 0163 def _DoTestCollection(vbtest, col_name, expected): 0164 # It sucks that some objects allow "Count()", but others "Count" 0165 def _getcount(ob): 0166 r = getattr(ob, "Count") 0167 if type(r)!=type(0): 0168 return r() 0169 return r 0170 c = getattr(vbtest, col_name) 0171 check = [] 0172 for item in c: 0173 check.append(item) 0174 if check != list(expected): 0175 raise error, "Collection %s didn't have %r (had %r)" % (col_name, expected, check) 0176 # Just looping over the collection again works (ie, is restartable) 0177 check = [] 0178 for item in c: 0179 check.append(item) 0180 if check != list(expected): 0181 raise error, "Collection 2nd time around %s didn't have %r (had %r)" % (col_name, expected, check) 0182 # Check we can get it via iter() 0183 i = iter(getattr(vbtest, col_name)) 0184 check = [] 0185 for item in i: 0186 check.append(item) 0187 if check != list(expected): 0188 raise error, "Collection iterator %s didn't have %r 2nd time around (had %r)" % (col_name, expected, check) 0189 # but an iterator is not restartable 0190 check = [] 0191 for item in i: 0192 check.append(item) 0193 if check != []: 0194 raise error, "2nd time around Collection iterator %s wasn't empty (had %r)" % (col_name, check) 0195 0196 # Check len()==Count() 0197 c = getattr(vbtest, col_name) 0198 if len(c) != _getcount(c): 0199 raise error, "Collection %s __len__(%r) wasn't==Count(%r)" % (col_name, len(c), _getcount(c)) 0200 # Check we can do it with zero based indexing. 0201 c = getattr(vbtest, col_name) 0202 check = [] 0203 for i in range(_getcount(c)): 0204 check.append(c[i]) 0205 if check != list(expected): 0206 raise error, "Collection %s didn't have %r (had %r)" % (col_name, expected, check) 0207 0208 # Check we can do it with our old "Skip/Next" methods. 0209 c = getattr(vbtest, col_name)._NewEnum() 0210 check = [] 0211 while 1: 0212 n = c.Next() 0213 if not n: 0214 break 0215 check.append(n[0]) 0216 if check != list(expected): 0217 raise error, "Collection %s didn't have %r (had %r)" % (col_name, expected, check) 0218 0219 def TestCollections(vbtest): 0220 _DoTestCollection(vbtest, "CollectionProperty", [1,"Two", "3"]) 0221 # zero based indexing works for simple VB collections. 0222 if vbtest.CollectionProperty[0] != 1: 0223 raise error, "The CollectionProperty[0] element was not the default value" 0224 0225 _DoTestCollection(vbtest, "EnumerableCollectionProperty", []) 0226 vbtest.EnumerableCollectionProperty.Add(1) 0227 vbtest.EnumerableCollectionProperty.Add("Two") 0228 vbtest.EnumerableCollectionProperty.Add("3") 0229 _DoTestCollection(vbtest, "EnumerableCollectionProperty", [1,"Two", "3"]) 0230 0231 def _DoTestArray(vbtest, data, expected_exception = None): 0232 try: 0233 vbtest.ArrayProperty = data 0234 if expected_exception is not None: 0235 raise error, "Expected '%s'" % expected_exception 0236 except expected_exception: 0237 return 0238 got = vbtest.ArrayProperty 0239 if got != data: 0240 raise error, \ 0241 "Could not set the array data correctly - got %r, expected %r" \ 0242 % (got, data) 0243 0244 def TestArrays(vbtest, bUseGenerated): 0245 # Try and use a safe array (note that the VB code has this declared as a VARIANT 0246 # and I cant work out how to force it to use native arrays! 0247 # (NOTE Python will convert incoming arrays to tuples, so we pass a tuple, even tho 0248 # a list works fine - just makes it easier for us to compare the result! 0249 # Empty array 0250 _DoTestArray(vbtest, ()) 0251 # Empty child array 0252 _DoTestArray(vbtest, ((), ())) 0253 # ints 0254 _DoTestArray(vbtest, tuple(range(1,100))) 0255 # Floats 0256 _DoTestArray(vbtest, (1.0, 2.0, 3.0)) 0257 # Strings. 0258 _DoTestArray(vbtest, tuple(string.split("Hello from Python"))) 0259 # Date and Time? 0260 # COM objects. 0261 _DoTestArray(vbtest, (vbtest, vbtest)) 0262 # Mixed 0263 _DoTestArray(vbtest, (1, 2.0, "3")) 0264 # Array alements containing other arrays 0265 _DoTestArray(vbtest, (1,(vbtest, vbtest),("3","4"))) 0266 # Multi-dimensional 0267 _DoTestArray(vbtest, (( (1,2,3), (4,5,6) ))) 0268 _DoTestArray(vbtest, (( (vbtest,vbtest,vbtest), (vbtest,vbtest,vbtest) ))) 0269 # Another dimension! 0270 arrayData = ( ((1,2),(3,4),(5,6)), ((7,8),(9,10),(11,12)) ) 0271 arrayData = ( ((vbtest,vbtest),(vbtest,vbtest),(vbtest,vbtest)), 0272 ((vbtest,vbtest),(vbtest,vbtest),(vbtest,vbtest)) ) 0273 _DoTestArray(vbtest, arrayData) 0274 0275 # Check that when a '__getitem__ that fails' object is the first item 0276 # in the structure, we don't mistake it for a sequence. 0277 _DoTestArray(vbtest, (vbtest, 2.0, "3")) 0278 _DoTestArray(vbtest, (1, 2.0, vbtest)) 0279 0280 # Pass arbitrarily sized arrays - these used to fail, but thanks to 0281 # Stefan Schukat, they now work! 0282 expected_exception = None 0283 arrayData = ( ((1,2,1),(3,4),(5,6)), ((7,8),(9,10),(11,12)) ) 0284 _DoTestArray(vbtest, arrayData, expected_exception) 0285 arrayData = ( ((vbtest,vbtest),), ((vbtest,),)) 0286 _DoTestArray(vbtest, arrayData, expected_exception) 0287 # Pass bad data - last item wrong size 0288 arrayData = ( ((1,2),(3,4),(5,6,8)), ((7,8),(9,10),(11,12)) ) 0289 _DoTestArray(vbtest, arrayData, expected_exception) 0290 0291 # byref safearray results with incorrect size. 0292 callback_ob = wrap(TestObject(), useDispatcher = useDispatcher) 0293 print "** Expecting a 'ValueError' exception to be printed next:" 0294 try: 0295 vbtest.DoCallbackSafeArraySizeFail(callback_ob) 0296 except pythoncom.com_error, (hr, msg, exc, arg): 0297 assert exc[1] == "Python COM Server Internal Error", "Didnt get the correct exception - '%s'" % (exc,) 0298 0299 if bUseGenerated: 0300 # This one is a bit strange! The array param is "ByRef", as VB insists. 0301 # The function itself also _returns_ the arram param. 0302 # Therefore, Python sees _2_ result values - one for the result, 0303 # and one for the byref. 0304 testData = string.split("Mark was here") 0305 resultData, byRefParam = vbtest.PassSAFEARRAY(testData) 0306 # Un unicode everything (only 1.5.2) 0307 try: 0308 unicode 0309 except NameError : # No builtin named Unicode! 0310 resultData = map(str, resultData) 0311 byRefParam = map(str, byRefParam) 0312 if testData != list(resultData): 0313 raise error, "The safe array data was not what we expected - got " + str(resultData) 0314 if testData != list(byRefParam): 0315 raise error, "The safe array data was not what we expected - got " + str(byRefParam) 0316 testData = [1.0, 2.0, 3.0] 0317 resultData, byRefParam = vbtest.PassSAFEARRAYVariant(testData) 0318 assert testData == list(byRefParam) 0319 assert testData == list(resultData) 0320 testData = ["hi", "from", "Python"] 0321 resultData, byRefParam = vbtest.PassSAFEARRAYVariant(testData) 0322 assert testData == list(byRefParam), "Expected '%s', got '%s'" % (testData, list(byRefParam)) 0323 assert testData == list(resultData), "Expected '%s', got '%s'" % (testData, list(resultData)) 0324 # This time, instead of an explicit str() for 1.5, we just 0325 # pass Unicode, so the result should compare equal 0326 testData = [1, 2.0, pythoncom.Unicode("3")] 0327 resultData, byRefParam = vbtest.PassSAFEARRAYVariant(testData) 0328 assert testData == list(byRefParam) 0329 assert testData == list(resultData) 0330 print "Array tests passed" 0331 0332 def TestStructs(vbtest): 0333 try: 0334 vbtest.IntProperty = "One" 0335 raise error, "Should have failed by now" 0336 except pythoncom.com_error, (hr, desc, exc, argErr): 0337 if hr != winerror.DISP_E_TYPEMISMATCH: 0338 raise error, "Expected DISP_E_TYPEMISMATCH" 0339 0340 s = vbtest.StructProperty 0341 if s.int_val != 99 or str(s.str_val) != "hello": 0342 raise error, "The struct value was not correct" 0343 s.str_val = "Hi from Python" 0344 s.int_val = 11 0345 if s.int_val != 11 or str(s.str_val) != "Hi from Python": 0346 raise error, "The struct value didnt persist!" 0347 0348 if s.sub_val.int_val != 66 or str(s.sub_val.str_val) != "sub hello": 0349 raise error, "The sub-struct value was not correct" 0350 sub = s.sub_val 0351 sub.int_val = 22 0352 if sub.int_val != 22: 0353 print sub.int_val 0354 raise error, "The sub-struct value didnt persist!" 0355 0356 if s.sub_val.int_val != 22: 0357 print s.sub_val.int_val 0358 raise error, "The sub-struct value (re-fetched) didnt persist!" 0359 0360 if s.sub_val.array_val[0].int_val != 0 or str(s.sub_val.array_val[0].str_val) != "zero": 0361 print s.sub_val.array_val[0].int_val 0362 raise error, "The array element wasnt correct" 0363 s.sub_val.array_val[0].int_val = 99 0364 s.sub_val.array_val[1].int_val = 66 0365 if s.sub_val.array_val[0].int_val != 99 or \ 0366 s.sub_val.array_val[1].int_val != 66: 0367 print s.sub_val.array_val[0].int_val 0368 raise error, "The array element didnt persist." 0369 # Now pass the struct back to VB 0370 vbtest.StructProperty = s 0371 # And get it back again 0372 s = vbtest.StructProperty 0373 if s.int_val != 11 or str(s.str_val) != "Hi from Python": 0374 raise error, "After sending to VB, the struct value didnt persist!" 0375 if s.sub_val.array_val[0].int_val != 99: 0376 raise error, "After sending to VB, the struct array value didnt persist!" 0377 0378 # Now do some object equality tests. 0379 assert s==s 0380 assert s != s.sub_val 0381 import copy 0382 s2 = copy.copy(s) 0383 assert s is not s2 0384 assert s == s2 0385 s2.int_val = 123 0386 assert s != s2 0387 # Make sure everything works with functions 0388 s2 = vbtest.GetStructFunc() 0389 assert s==s2 0390 vbtest.SetStructSub(s2) 0391 0392 # Create a new structure, and set its elements. 0393 s = win32com.client.Record("VBStruct", vbtest) 0394 assert s.int_val == 0, "new struct inst initialized correctly!" 0395 s.int_val = -1 0396 vbtest.SetStructSub(s) 0397 assert vbtest.GetStructFunc().int_val == -1, "new struct didnt make the round trip!" 0398 # Finally, test stand-alone structure arrays. 0399 s_array = vbtest.StructArrayProperty 0400 assert s_array is None, "Expected None from the uninitialized VB array" 0401 vbtest.MakeStructArrayProperty(3) 0402 s_array = vbtest.StructArrayProperty 0403 assert len(s_array)==3 0404 for i in range(len(s_array)): 0405 assert s_array[i].int_val == i 0406 assert s_array[i].sub_val.int_val == i 0407 assert s_array[i].sub_val.array_val[0].int_val == i 0408 assert s_array[i].sub_val.array_val[1].int_val == i+1 0409 assert s_array[i].sub_val.array_val[2].int_val == i+2 0410 0411 # Some error type checks. 0412 try: 0413 s.bad_attribute 0414 raise RuntimeError, "Could get a bad attribute" 0415 except AttributeError: 0416 pass 0417 m = s.__members__ 0418 assert m[0]=="int_val" and m[1]=="str_val" and m[2]=="ob_val" and m[3]=="sub_val" 0419 0420 # NOTE - a COM error is _not_ acceptable here! 0421 print "Struct/Record tests passed" 0422 0423 def TestVBInterface(ob): 0424 t = ob.GetInterfaceTester(2) 0425 if t.getn() != 2: 0426 raise error, "Initial value wrong" 0427 t.setn(3) 0428 if t.getn() != 3: 0429 raise error, "New value wrong" 0430 0431 def DoTestAll(): 0432 o = win32com.client.Dispatch("PyCOMVBTest.Tester") 0433 TestVB(o,1) 0434 0435 o = win32com.client.dynamic.DumbDispatch("PyCOMVBTest.Tester") 0436 TestVB(o,0) 0437 0438 def TestAll(): 0439 if not __debug__: 0440 raise RuntimeError, "This must be run in debug mode - we use assert!" 0441 try: 0442 DoTestAll() 0443 print "All tests appear to have worked!" 0444 except: 0445 print "TestAll() failed!!" 0446 traceback.print_exc() 0447 0448 # Make this test run under our test suite to leak tests etc work 0449 def suite(): 0450 import unittest 0451 test = util.CapturingFunctionTestCase(TestAll, description="VB tests") 0452 suite = unittest.TestSuite() 0453 suite.addTest(test) 0454 return suite 0455 0456 if __name__=='__main__': 0457 util.testmain() 0458
Generated by PyXR 0.9.4