From 03ef4821459e4951ebc1072c8fa4931fb29991a9 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Jan 2026 15:07:56 +0900 Subject: [PATCH 1/6] test: Add test for `VARIANTEnumerator` in `test_server_automation.py` This commit introduces a new test file `test/test_server_automation.py` containing `TestVARIANTEnumerator`. This test class verifies the functionality by creating and enumerating `IDispatch` objects and asserting the correct behavior of the `Next` method of `IEnumVARIANT`. --- comtypes/test/test_server_automation.py | 48 +++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 comtypes/test/test_server_automation.py diff --git a/comtypes/test/test_server_automation.py b/comtypes/test/test_server_automation.py new file mode 100644 index 00000000..09673839 --- /dev/null +++ b/comtypes/test/test_server_automation.py @@ -0,0 +1,48 @@ +import unittest + +import comtypes.client +from comtypes.automation import IEnumVARIANT +from comtypes.server.automation import VARIANTEnumerator + +comtypes.client.GetModule("scrrun.dll") +from comtypes.gen import Scripting as scrrun + + +class TestVARIANTEnumerator(unittest.TestCase): + def setUp(self): + # Create a list of IDispatch objects to enumerate + dict1 = comtypes.client.CreateObject( + "Scripting.Dictionary", interface=scrrun.IDictionary + ) + dict1.Add("key1", "value1") + dict2 = comtypes.client.CreateObject( + "Scripting.Dictionary", interface=scrrun.IDictionary + ) + dict2.Add("key2", "value2") + dict3 = comtypes.client.CreateObject( + "Scripting.Dictionary", interface=scrrun.IDictionary + ) + dict3.Add("key3", "value3") + self.items = [dict1, dict2, dict3] + self.enumerator = VARIANTEnumerator(self.items) + + def test_Next(self): + enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) + # Retrieve the first item + item, fetched = enum_variant.Next(1) + self.assertEqual(fetched, 1) + dict1 = item.QueryInterface(scrrun.IDictionary) + self.assertEqual(dict1.Item("key1"), "value1") + # Retrieve the second item + item, fetched = enum_variant.Next(1) + dict2 = item.QueryInterface(scrrun.IDictionary) + self.assertEqual(dict2.Item("key2"), "value2") + # Retrieve the third item + item, fetched = enum_variant.Next(1) + self.assertEqual(fetched, 1) + dict3 = item.QueryInterface(scrrun.IDictionary) + self.assertEqual(dict3.Item("key3"), "value3") + # After all items are enumerated, `Next` should return 0 fetched + item, fetched = enum_variant.Next(1) + self.assertEqual(fetched, 0) + self.assertFalse(item) From c95614cb47c91265e1a95bffec9a41811a479f5c Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Jan 2026 15:07:56 +0900 Subject: [PATCH 2/6] test: Add test for `IEnumVARIANT.Next` with multiple items Refactored `test_Next` to `test_Next_single_item` and added `test_Next_multiple_items` to `TestVARIANTEnumerator` in `test_server_automation.py`. This new test verifies that `IEnumVARIANT.Next` can correctly fetch multiple items at once, ensuring proper handling of the `celt` parameter. --- comtypes/test/test_server_automation.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/comtypes/test/test_server_automation.py b/comtypes/test/test_server_automation.py index 09673839..16f357f5 100644 --- a/comtypes/test/test_server_automation.py +++ b/comtypes/test/test_server_automation.py @@ -26,7 +26,7 @@ def setUp(self): self.items = [dict1, dict2, dict3] self.enumerator = VARIANTEnumerator(self.items) - def test_Next(self): + def test_Next_single_item(self): enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) # Retrieve the first item item, fetched = enum_variant.Next(1) @@ -46,3 +46,20 @@ def test_Next(self): item, fetched = enum_variant.Next(1) self.assertEqual(fetched, 0) self.assertFalse(item) + + def test_Next_multiple_items(self): + enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) + # Retrieve all three items at once. + # We can now call Next(celt) with celt != 1, the call always returns a + # list: + item1, item2, item3 = enum_variant.Next(3) + dict1 = item1.QueryInterface(scrrun.IDictionary) + self.assertEqual(dict1.Item("key1"), "value1") + dict2 = item2.QueryInterface(scrrun.IDictionary) + self.assertEqual(dict2.Item("key2"), "value2") + dict3 = item3.QueryInterface(scrrun.IDictionary) + self.assertEqual(dict3.Item("key3"), "value3") + # After all items are enumerated, Next should return 0 fetched + item, fetched = enum_variant.Next(1) + self.assertEqual(fetched, 0) + self.assertFalse(item) From 7dbb751a9ca0541dae078fb76051c63d37093ce3 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Jan 2026 15:07:56 +0900 Subject: [PATCH 3/6] test: Add test for `IEnumVARIANT.Skip` method This commit introduces a new test method `test_Skip` to `TestVARIANTEnumerator` in `test_server_automation.py`. This test verifies the functionality of `IEnumVARIANT.Skip` by testing various skip scenarios, including skipping zero items, a single item, and more items than available, asserting correct return values for `Skip` and subsequent `Next` calls. --- comtypes/test/test_server_automation.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/comtypes/test/test_server_automation.py b/comtypes/test/test_server_automation.py index 16f357f5..23ef0e60 100644 --- a/comtypes/test/test_server_automation.py +++ b/comtypes/test/test_server_automation.py @@ -1,6 +1,7 @@ import unittest import comtypes.client +import comtypes.hresult as hresult from comtypes.automation import IEnumVARIANT from comtypes.server.automation import VARIANTEnumerator @@ -63,3 +64,23 @@ def test_Next_multiple_items(self): item, fetched = enum_variant.Next(1) self.assertEqual(fetched, 0) self.assertFalse(item) + + def test_Skip(self): + enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) + # Explicitly reset the enumerator, though it should be fresh + self.assertEqual(enum_variant.Reset(), hresult.S_OK) + # Skip zero items, should return S_OK + self.assertEqual(enum_variant.Skip(0), hresult.S_OK) + # Skip the first item + self.assertEqual(enum_variant.Skip(1), hresult.S_OK) + # Next should return the second item + item, fetched = enum_variant.Next(1) + self.assertEqual(fetched, 1) + dict2 = item.QueryInterface(scrrun.IDictionary) + self.assertEqual(dict2.Item("key2"), "value2") + # Skip remaining items (1 items available, but skip 2) + self.assertEqual(enum_variant.Skip(2), hresult.S_FALSE) + # Next should now return 0 fetched + item, fetched = enum_variant.Next(1) + self.assertEqual(fetched, 0) + self.assertFalse(item) From 355b8adc6dfc559747257d7081e4fb80a764bb19 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Jan 2026 15:07:56 +0900 Subject: [PATCH 4/6] test: Add test for `IEnumVARIANT.Reset` method This commit introduces a new test method `test_Reset` to `TestVARIANTEnumerator` in `test/test_server_automation.py`. This test verifies the functionality of `IEnumVARIANT.Reset` by advancing the enumerator, resetting it, and then asserting that subsequent `Next` calls return items from the beginning of the enumeration. --- comtypes/test/test_server_automation.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/comtypes/test/test_server_automation.py b/comtypes/test/test_server_automation.py index 23ef0e60..80915866 100644 --- a/comtypes/test/test_server_automation.py +++ b/comtypes/test/test_server_automation.py @@ -84,3 +84,19 @@ def test_Skip(self): item, fetched = enum_variant.Next(1) self.assertEqual(fetched, 0) self.assertFalse(item) + + def test_Reset(self): + enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) + # Get some items + item, fetched = enum_variant.Next(1) + self.assertEqual(item.QueryInterface(scrrun.IDictionary).Item("key1"), "value1") + item, fetched = enum_variant.Next(1) + self.assertEqual(item.QueryInterface(scrrun.IDictionary).Item("key2"), "value2") + # Reset the enumerator + hr = enum_variant.Reset() + self.assertEqual(hr, hresult.S_OK) + # Next should return the first item again + item, fetched = enum_variant.Next(1) + self.assertEqual(fetched, 1) + # Verify the content of the first dictionary + self.assertEqual(item.QueryInterface(scrrun.IDictionary).Item("key1"), "value1") From 34ac6472b9c67b744c09ac9e396b6169172e90f6 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Jan 2026 15:07:56 +0900 Subject: [PATCH 5/6] test: Add test for `IEnumVARIANT.Clone` method (results in `E_NOTIMPL`) This commit introduces a new test method `test_Clone` to `TestVARIANTEnumerator` in `test_server_automation.py`. This test verifies that calling `IEnumVARIANT.Clone` on a `VARIANTEnumerator` raises a `COMError` with `hresult.E_NOTIMPL`, as the `Clone` method is not implemented. --- comtypes/test/test_server_automation.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/comtypes/test/test_server_automation.py b/comtypes/test/test_server_automation.py index 80915866..34239d09 100644 --- a/comtypes/test/test_server_automation.py +++ b/comtypes/test/test_server_automation.py @@ -1,4 +1,5 @@ import unittest +from _ctypes import COMError import comtypes.client import comtypes.hresult as hresult @@ -100,3 +101,10 @@ def test_Reset(self): self.assertEqual(fetched, 1) # Verify the content of the first dictionary self.assertEqual(item.QueryInterface(scrrun.IDictionary).Item("key1"), "value1") + + def test_Clone(self): + enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) + # Clone is not implemented in `VARIANTEnumerator`. + with self.assertRaises(COMError) as cm: + enum_variant.Clone() + self.assertEqual(cm.exception.hresult, hresult.E_NOTIMPL) From ef025458440198f16999bdaf9b2e994ff3b9bde3 Mon Sep 17 00:00:00 2001 From: junkmd Date: Sat, 24 Jan 2026 15:07:56 +0900 Subject: [PATCH 6/6] test: Add tests for `VARIANTEnumerator` Python protocol support This commit introduces new test methods `test_dunder_iter` and `test_dunder_getitem` to `TestVARIANTEnumerator` in `test/test_server_automation.py`. `test_dunder_iter` verifies iteration support for `IEnumVARIANT` through `VARIANTEnumerator`. `test_dunder_getitem` confirms indexed access support and proper `IndexError` handling for out-of-bounds access. --- comtypes/test/test_server_automation.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/comtypes/test/test_server_automation.py b/comtypes/test/test_server_automation.py index 34239d09..98cd8f73 100644 --- a/comtypes/test/test_server_automation.py +++ b/comtypes/test/test_server_automation.py @@ -108,3 +108,28 @@ def test_Clone(self): with self.assertRaises(COMError) as cm: enum_variant.Clone() self.assertEqual(cm.exception.hresult, hresult.E_NOTIMPL) + + def test_dunder_iter(self): + enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) + # Ensure the enumerator is reset before iterating + enum_variant.Reset() + dict1, dict2, dict3 = [ + i.QueryInterface(scrrun.IDictionary) for i in enum_variant + ] + self.assertEqual(dict1["key1"], "value1") + self.assertEqual(dict2["key2"], "value2") + self.assertEqual(dict3["key3"], "value3") + + def test_dunder_getitem(self): + enum_variant = self.enumerator.QueryInterface(IEnumVARIANT) + enum_variant.Reset() + # Directly access items by index + dict1 = enum_variant[0].QueryInterface(scrrun.IDictionary) + self.assertEqual(dict1["key1"], "value1") + dict2 = enum_variant[1].QueryInterface(scrrun.IDictionary) + self.assertEqual(dict2["key2"], "value2") + dict3 = enum_variant[2].QueryInterface(scrrun.IDictionary) + self.assertEqual(dict3["key3"], "value3") + # Test index out of bounds + with self.assertRaises(IndexError): + _ = enum_variant[len(self.items)]