diff --git a/comtypes/test/test_comserver.py b/comtypes/test/test_comserver.py index ee0b7cdc..e7e9636b 100644 --- a/comtypes/test/test_comserver.py +++ b/comtypes/test/test_comserver.py @@ -1,41 +1,44 @@ -import sys +import doctest import unittest +from ctypes import pointer +from typing import Any import comtypes.test.TestComServer +from comtypes import BSTR from comtypes.client import CreateObject -from comtypes.server.register import register # , unregister +from comtypes.server.register import register, unregister from comtypes.test import is_resource_enabled from comtypes.test.find_memleak import find_memleak def setUpModule(): - raise unittest.SkipTest( - "This test requires the tests to be run as admin since it tries to " - "register the test COM server. Is this a good idea?" - ) + try: + register(comtypes.test.TestComServer.TestComServer) + except WindowsError as e: + if e.winerror != 5: # [Error 5] Access is denied + raise e + raise unittest.SkipTest( + "This test requires the tests to be run as admin since it tries to " + "register the test COM server." + ) - # If this test is ever NOT skipped, then this line needs to run. Keeping it here for posterity. - register(comtypes.test.TestComServer.TestComServer) +def tearDownModule(): + unregister(comtypes.test.TestComServer.TestComServer) -class TestInproc(unittest.TestCase): - def create_object(self): - return CreateObject( - "TestComServerLib.TestComServer", clsctx=comtypes.CLSCTX_INPROC_SERVER - ) + +class BaseServerTest(object): + def create_object(self) -> Any: ... def _find_memleak(self, func): bytes = find_memleak(func) - self.assertFalse(bytes, "Leaks %d bytes" % bytes) + self.assertFalse(bytes, "Leaks %d bytes" % bytes) # type: ignore def test_mixedinout(self): o = self.create_object() - self.assertEqual(o.MixedInOut(2, 4), (3, 5)) + self.assertEqual(o.MixedInOut(2, 4), (3, 5)) # type: ignore def test_getname(self): - from ctypes import pointer - from comtypes import BSTR - # This tests a tricky bug, introduced with this patch: # http://www.python.org/sf/1643874 # @@ -53,61 +56,70 @@ def test_getname(self): for i in range(10): BSTR("f" * len(name)) # Make sure the pointer is still valid: - self.assertEqual(pb[0], name) + self.assertEqual(pb[0], name) # type: ignore - if is_resource_enabled("memleaks"): + def test_get_id(self): + obj = self.create_object() + self._find_memleak(lambda: obj.id) - def test_get_id(self): - obj = self.create_object() - self._find_memleak(lambda: obj.id) + def test_get_name(self): + obj = self.create_object() + self._find_memleak(lambda: obj.name) - def test_get_name(self): - obj = self.create_object() - self._find_memleak(lambda: obj.name) + def test_set_name(self): + obj = self.create_object() - def test_set_name(self): - obj = self.create_object() + def func(): + obj.name = "abcde" - def func(): - obj.name = "abcde" + self._find_memleak(func) - self._find_memleak(func) + def test_SetName(self): + obj = self.create_object() - def test_SetName(self): - obj = self.create_object() + def func(): + obj.SetName("abcde") - def func(): - obj.SetName("abcde") + self._find_memleak(func) - self._find_memleak(func) + def test_eval(self): + obj = self.create_object() - def test_eval(self): - obj = self.create_object() + def func(): + return obj.eval("(1, 2, 3)") - def func(): - return obj.eval("(1, 2, 3)") + self.assertEqual(func(), (1, 2, 3)) # type: ignore + self._find_memleak(func) - self.assertEqual(func(), (1, 2, 3)) - self._find_memleak(func) + def test_get_typeinfo(self): + obj = self.create_object() - def test_get_typeinfo(self): - obj = self.create_object() + def func(): + obj.GetTypeInfo(0) + obj.GetTypeInfoCount() + obj.QueryInterface(comtypes.IUnknown) - def func(): - obj.GetTypeInfo(0) - obj.GetTypeInfoCount() - obj.QueryInterface(comtypes.IUnknown) + self._find_memleak(func) - self._find_memleak(func) +class TestInproc(BaseServerTest, unittest.TestCase): + def create_object(self): + return CreateObject( + "TestComServerLib.TestComServer", clsctx=comtypes.CLSCTX_INPROC_SERVER + ) -if is_resource_enabled("ui"): - class TestLocalServer(TestInproc): - def create_object(self): - return CreateObject( - "TestComServerLib.TestComServer", clsctx=comtypes.CLSCTX_LOCAL_SERVER - ) +class TestLocalServer(BaseServerTest, unittest.TestCase): + def create_object(self): + return CreateObject( + "TestComServerLib.TestComServer", clsctx=comtypes.CLSCTX_LOCAL_SERVER + ) + + @unittest.skip("This fails. Why?") + def test_get_typeinfo(self): + # Calling `GetTypeInfo` occurs; + # OSError: exception: access violation reading 0x0000000000000000 + pass try: @@ -116,6 +128,7 @@ def create_object(self): pass else: + @unittest.skip("This depends on 'pywin32'.") class TestInproc_win32com(TestInproc): def create_object(self): return Dispatch("TestComServerLib.TestComServer") @@ -134,6 +147,7 @@ def test_mixedinout(self): if is_resource_enabled("ui"): + @unittest.skip("This depends on 'pywin32'.") class TestLocalServer_win32com(TestInproc_win32com): def create_object(self): return Dispatch( @@ -142,72 +156,50 @@ def create_object(self): ) -import doctest -import comtypes.test.test_comserver - - class TestCase(unittest.TestCase): def test(self): + import comtypes.test.test_comserver + doctest.testmod(comtypes.test.test_comserver, optionflags=doctest.ELLIPSIS) # The following functions are never called, they only contain doctests: - if sys.version_info >= (3, 0): - - def ShowEvents(self): - """ - >>> from comtypes.client import CreateObject, ShowEvents - >>> - >>> o = CreateObject("TestComServerLib.TestComServer") - >>> con = ShowEvents(o) - # event found: ITestComServerEvents_EvalStarted - # event found: ITestComServerEvents_EvalCompleted - >>> result = o.eval("10. / 4") - Event ITestComServerEvents_EvalStarted(None, '10. / 4') - Event ITestComServerEvents_EvalCompleted(None, '10. / 4', VARIANT(vt=0x5, 2.5)) - >>> result - 2.5 - >>> - """ - - else: - - def ShowEvents(self): - """ - >>> from comtypes.client import CreateObject, ShowEvents - >>> - >>> o = CreateObject("TestComServerLib.TestComServer") - >>> con = ShowEvents(o) - # event found: ITestComServerEvents_EvalStarted - # event found: ITestComServerEvents_EvalCompleted - >>> result = o.eval("10. / 4") - Event ITestComServerEvents_EvalStarted(None, u'10. / 4') - Event ITestComServerEvents_EvalCompleted(None, u'10. / 4', VARIANT(vt=0x5, 2.5)) - >>> result - 2.5 - >>> - """ - - # The following test, if enabled, works but the testsuit - # crashes elsewhere. Is there s problem with SAFEARRAYs? - - if is_resource_enabled("CRASHES"): - - def Fails(self): - """ - >>> from comtypes.client import CreateObject, ShowEvents - >>> - >>> o = CreateObject("TestComServerLib.TestComServer") - >>> con = ShowEvents(o) - # event found: ITestComServerEvents_EvalStarted - # event found: ITestComServerEvents_EvalCompleted - >>> result = o.eval("['32'] * 2") - Event ITestComServerEvents_EvalStarted(None, u"['32'] * 2") - Event ITestComServerEvents_EvalCompleted(None, u"['32'] * 2", VARIANT(vt=0x200c, (u'32', u'32'))) - >>> result - (u'32', u'32') - >>> - """ + def ShowEventsFloat(self): + """ + >>> from comtypes.client import CreateObject, ShowEvents + >>> + >>> o = CreateObject("TestComServerLib.TestComServer") + >>> con = ShowEvents(o) + # event found: ITestComServerEvents_EvalStarted + # event found: ITestComServerEvents_EvalCompleted + >>> result = o.eval("10. / 4") + Event ITestComServerEvents_EvalStarted(None, '10. / 4') + Event ITestComServerEvents_EvalCompleted(None, '10. / 4', VARIANT(vt=0x5, 2.5)) + >>> result + 2.5 + >>> + """ + + # # The following test, if enabled, works but the testsuit + # # crashes elsewhere. Is there s problem with SAFEARRAYs? + + # if is_resource_enabled("CRASHES"): + + # def Fails(self): + # """ + # >>> from comtypes.client import CreateObject, ShowEvents + # >>> + # >>> o = CreateObject("TestComServerLib.TestComServer") + # >>> con = ShowEvents(o) + # # event found: ITestComServerEvents_EvalStarted + # # event found: ITestComServerEvents_EvalCompleted + # >>> result = o.eval("['32'] * 2") + # Event ITestComServerEvents_EvalStarted(None, u"['32'] * 2") + # Event ITestComServerEvents_EvalCompleted(None, u"['32'] * 2", VARIANT(vt=0x200c, (u'32', u'32'))) + # >>> result + # (u'32', u'32') + # >>> + # """ def GetEvents(self): """