Skip to content

Commit 2007a07

Browse files
committed
test: Add IStorage.Stat tests.
Introduced `test_Stat` in `test_storage.py` to thoroughly verify the behavior of the `IStorage.Stat` method, including error handling for invalid flags and correct retrieval of `tagSTATSTG` information. The `_create_docfile` helper method was updated to allow specifying a file path, enabling more precise control over test document creation and allowing for the validation of temporary file creation and existence.
1 parent 3cd821a commit 2007a07

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

comtypes/test/test_storage.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1+
import tempfile
12
import unittest
23
from _ctypes import COMError
34
from ctypes import HRESULT, POINTER, OleDLL, byref, c_ubyte
45
from ctypes.wintypes import DWORD, PWCHAR
56
from pathlib import Path
7+
from typing import Optional
68

79
import comtypes
810
import comtypes.client
911

1012
comtypes.client.GetModule("portabledeviceapi.dll")
11-
from comtypes.gen.PortableDeviceApiLib import IStorage
13+
from comtypes.gen.PortableDeviceApiLib import IStorage, tagSTATSTG
14+
15+
STGTY_STORAGE = 1
1216

1317
STATFLAG_DEFAULT = 0
1418
STGC_DEFAULT = 0
@@ -23,7 +27,7 @@
2327
STREAM_SEEK_SET = 0
2428

2529
STG_E_PATHNOTFOUND = -2147287038
26-
30+
STG_E_INVALIDFLAG = -2147286785
2731

2832
_ole32 = OleDLL("ole32")
2933

@@ -39,13 +43,16 @@ class Test_IStorage(unittest.TestCase):
3943
CREATE_TESTDOC = STGM_DIRECT | STGM_CREATE | RW_EXCLUSIVE
4044
CREATE_TEMP_TESTDOC = CREATE_TESTDOC | STGM_DELETEONRELEASE
4145

42-
def _create_docfile(self, mode: int) -> IStorage:
46+
def _create_docfile(self, mode: int, name: Optional[str] = None) -> IStorage:
4347
stg = POINTER(IStorage)()
44-
_StgCreateDocfile(None, mode, 0, byref(stg))
48+
_StgCreateDocfile(name, mode, 0, byref(stg))
4549
return stg # type: ignore
4650

4751
def test_CreateStream(self):
4852
storage = self._create_docfile(mode=self.CREATE_TEMP_TESTDOC)
53+
# When created with `StgCreateDocfile(NULL, ...)`, `pwcsName` is a
54+
# temporary filename. The file really exists on disk because Windows
55+
# creates an actual temporary file for the compound storage.
4956
filepath = Path(storage.Stat(STATFLAG_DEFAULT).pwcsName)
5057
self.assertTrue(filepath.exists())
5158
stream = storage.CreateStream("example", self.RW_EXCLUSIVE_CREATE, 0, 0)
@@ -151,3 +158,30 @@ def test_SetClass(self):
151158
# Re-set CLSID to CLSID_NULL and verify it is correctly set.
152159
storage.SetClass(comtypes.GUID())
153160
self.assertEqual(storage.Stat(STATFLAG_DEFAULT).clsid, comtypes.GUID())
161+
162+
def test_Stat(self):
163+
with tempfile.TemporaryDirectory() as t:
164+
tmpdir = Path(t)
165+
tmpfile = tmpdir / "test_docfile.cfs"
166+
self.assertFalse(tmpfile.exists())
167+
# When created with `StgCreateDocfile(filepath_string, ...)`, the
168+
# compound file is created at that location.
169+
storage = self._create_docfile(
170+
name=str(tmpfile), mode=self.CREATE_TEMP_TESTDOC
171+
)
172+
self.assertTrue(tmpfile.exists())
173+
with self.assertRaises(COMError) as cm:
174+
storage.Stat(0xFFFFFFFF) # Invalid flag
175+
self.assertEqual(cm.exception.hresult, STG_E_INVALIDFLAG)
176+
stat = storage.Stat(STATFLAG_DEFAULT)
177+
self.assertIsInstance(stat, tagSTATSTG)
178+
del storage # Release the storage to prevent 'cannot access the file ...'
179+
self.assertEqual(stat.type, STGTY_STORAGE)
180+
# Due to header overhead and file system allocation, the size may be
181+
# greater than 0 bytes.
182+
self.assertGreaterEqual(stat.cbSize, 0)
183+
# `grfMode` should reflect the access mode flags from creation.
184+
self.assertEqual(stat.grfMode, self.RW_EXCLUSIVE | STGM_DIRECT)
185+
self.assertEqual(stat.grfLocksSupported, 0)
186+
self.assertEqual(stat.clsid, comtypes.GUID()) # CLSID_NULL for new creation.
187+
self.assertEqual(stat.grfStateBits, 0)

0 commit comments

Comments
 (0)