Skip to content

Commit

Permalink
Added tests for the 'pythoncom.com_record' subclassing functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
geppi committed Jan 9, 2025
1 parent c9aeec2 commit ed5fe41
Showing 1 changed file with 124 additions and 25 deletions.
149 changes: 124 additions & 25 deletions com/win32com/test/testPyComTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@
import win32com.test.util
import win32timezone
import winerror
from win32com.client import VARIANT, CastTo, DispatchBaseClass, constants
from win32com.client import (
VARIANT,
CastTo,
DispatchBaseClass,
constants,
Record,
register_record_class,
)

Check failure on line 28 in com/win32com/test/testPyComTest.py

View workflow job for this annotation

GitHub Actions / checkers

Ruff (I001)

com\win32com\test\testPyComTest.py:7:1: I001 Import block is un-sorted or un-formatted
importMsg = "**** PyCOMTest is not installed ***\n PyCOMTest is a Python test specific COM client and server.\n It is likely this server is not installed on this machine\n To install the server, you must get the win32com sources\n and build it using MS Visual C++"

Expand Down Expand Up @@ -45,6 +52,46 @@
verbose = 0


# Subclasses of pythoncom.com_record.
# Registration is performed in 'TestGenerated'.
class TestStruct1(pythoncom.com_record):

Check failure on line 57 in com/win32com/test/testPyComTest.py

View workflow job for this annotation

GitHub Actions / checkers

Ruff (C408)

com\win32com\test\testPyComTest.py:57:17: C408 Unnecessary `tuple()` call (rewrite as a literal)
__slots__ = tuple()
TLBID = "{6BCDCB60-5605-11D0-AE5F-CADD4C000000}"
MJVER = 1
MNVER = 1
LCID = 0
GUID = "{7A4CE6A7-7959-4E85-A3C0-B41442FF0F67}"


class TestStruct2(pythoncom.com_record):

Check failure on line 66 in com/win32com/test/testPyComTest.py

View workflow job for this annotation

GitHub Actions / checkers

Ruff (C408)

com\win32com\test\testPyComTest.py:66:17: C408 Unnecessary `tuple()` call (rewrite as a literal)
__slots__ = tuple()
TLBID = "{6BCDCB60-5605-11D0-AE5F-CADD4C000000}"
MJVER = 1
MNVER = 1
LCID = 0
GUID = "{78F0EA07-B7CF-42EA-A251-A4C6269F76AF}"


# We don't need to stick with the struct name in the TypeLibrry for the subclass name.
# The following class has the same GUID as TestStruct2 from the TypeLibrary.
class ArrayOfStructsTestStruct(pythoncom.com_record):

Check failure on line 77 in com/win32com/test/testPyComTest.py

View workflow job for this annotation

GitHub Actions / checkers

Ruff (C408)

com\win32com\test\testPyComTest.py:77:17: C408 Unnecessary `tuple()` call (rewrite as a literal)
__slots__ = tuple()
TLBID = "{6BCDCB60-5605-11D0-AE5F-CADD4C000000}"
MJVER = 1
MNVER = 1
LCID = 0
GUID = "{78F0EA07-B7CF-42EA-A251-A4C6269F76AF}"


class NotInTypeLibraryTestStruct(pythoncom.com_record):

Check failure on line 86 in com/win32com/test/testPyComTest.py

View workflow job for this annotation

GitHub Actions / checkers

Ruff (C408)

com\win32com\test\testPyComTest.py:86:17: C408 Unnecessary `tuple()` call (rewrite as a literal)
__slots__ = tuple()
TLBID = "{6BCDCB60-5605-11D0-AE5F-CADD4C000000}"
MJVER = 1
MNVER = 1
LCID = 0
GUID = "{79BB6AC3-12DE-4AC5-88AC-225C29A58043}"


def check_get_set(func, arg):
got = func(arg)
assert got == arg, f"{func} failed - expected {arg!r}, got {got!r}"
Expand Down Expand Up @@ -198,18 +245,6 @@ def TestCommon(o, is_generated):
progress("Checking structs")
r = o.GetStruct()
assert r.int_value == 99 and str(r.str_value) == "Hello from C++"
# Dynamic does not support struct byref as [ in, out ] parameters
if hasattr(o, "CLSID"):
progress("Checking struct byref as [ in, out ] parameter")
mod_r = o.ModifyStruct(r)
# We expect the input value to stay unchanged
assert r.int_value == 99 and str(r.str_value) == "Hello from C++"
# and the return value to reflect the modifications performed on the COM server side
assert (
mod_r.int_value == 100
and str(mod_r.str_value) == "Nothing is as constant as change"
)

assert o.DoubleString("foo") == "foofoo"

progress("Checking var args")
Expand Down Expand Up @@ -409,9 +444,46 @@ def TestDynamic():
# assert o.ParamProp(0) == 1, o.paramProp(0)


def TestStructByref(o, r):
progress("Checking struct byref as [ in, out ] parameter")
mod_r = o.ModifyStruct(r)
# If 'TestStruct1' was registered as an instantiable subclass
# of pythoncom.com_record, the return value should have this type.
if isinstance(r, TestStruct1):
assert type(mod_r) is TestStruct1
else:
assert type(mod_r) is pythoncom.com_record
# We expect the input value to stay unchanged
assert r.int_value == 99 and str(r.str_value) == "Hello from C++"
# and the return value to reflect the modifications performed on the COM server side
assert (
mod_r.int_value == 100
and str(mod_r.str_value) == "Nothing is as constant as change"
)


def TestArrayOfStructs(o, test_rec):
progress("Testing struct with SAFEARRAY(VT_RECORD) fields.")
rec_list = []
for i in range(3):
# If 'ArrayOfStructsTestStruct' and 'TestStruct1' were registered as instantiable
# subclasses of pythoncom.com_record, we expect to work with these types.
if isinstance(test_rec, ArrayOfStructsTestStruct):
rec = TestStruct1()
assert type(rec) is TestStruct1
else:
rec = Record("TestStruct1", o)
assert type(rec) is pythoncom.com_record
rec.str_value = "This is record number"
rec.int_value = i + 1
rec_list.append(rec)
test_rec.array_of_records = rec_list
test_rec.rec_count = i + 1
assert o.VerifyArrayOfStructs(test_rec)


def TestGenerated():
# Create an instance of the server.
from win32com.client import Record
from win32com.client.gencache import EnsureDispatch

o = EnsureDispatch("PyCOMTest.PyCOMTest")
Expand All @@ -434,18 +506,45 @@ def TestGenerated():
coclass = GetClass("{B88DD310-BAE8-11D0-AE86-76F2C1000000}")()
TestCounter(coclass, True)

# Test records with SAFEARRAY(VT_RECORD) fields.
progress("Testing records with SAFEARRAY(VT_RECORD) fields.")
l = []
for i in range(3):
rec = Record("TestStruct1", o)
rec.str_value = "This is record number"
rec.int_value = i + 1
l.append(rec)
# Test plain pythoncom.com_record structs.
progress("Testing baseclass pythoncom.com_record structs.")
r = o.GetStruct()
assert type(r) is pythoncom.com_record
TestStructByref(o, r)
test_rec = Record("TestStruct2", o)
test_rec.array_of_records = l
test_rec.rec_count = i + 1
assert o.VerifyArrayOfStructs(test_rec)
assert type(test_rec) is pythoncom.com_record
TestArrayOfStructs(o, test_rec)

progress("Testing registration of pythoncom.com_record subclasses.")
# Instantiating a pythoncom.com_record subclass, which has proper GUID attributes,
# does return an instance of the base class, as long as we have not registered it.
r_base = TestStruct1()
assert type(r_base) is pythoncom.com_record
# Register the subclasses in pythoncom.
register_record_class(TestStruct1)
register_record_class(ArrayOfStructsTestStruct)
# Now the type of the instance is the registered subclass.
r_sub = TestStruct1()
assert type(r_sub) is TestStruct1
# Now also the 'Record' factory function returns an instance of the registered subtype.
r_sub = Record("TestStruct1", o)
assert type(r_sub) is TestStruct1
# It should not be possible to register multiple classes with the same GUID, e.g.
# 'TestStruct2' has the same GUID class attribute value as 'ArrayOfStructsTestStruct'.
check_get_set_raises(ValueError, register_record_class, TestStruct2)
# Also registering a class with a GUID that is not in the TypeLibrary should fail.
check_get_set_raises(TypeError, register_record_class, NotInTypeLibraryTestStruct)

# Perform the 'Byref' and 'ArrayOfStruct tests using the registered subclasses.
progress("Testing subclasses of pythoncom.com_record.")
r = o.GetStruct()
# After 'TestStruct1' was registered as an instantiable subclass
# of pythoncom.com_record, the return value should have this type.
assert type(r) is TestStruct1
TestStructByref(o, r)
test_rec = ArrayOfStructsTestStruct()
assert type(test_rec) is ArrayOfStructsTestStruct
TestArrayOfStructs(o, test_rec)

# XXX - this is failing in dynamic tests, but should work fine.
i1, i2 = o.GetMultipleInterfaces()
Expand Down

0 comments on commit ed5fe41

Please sign in to comment.