2024-10-02 22:15:59 +04:00

172 lines
5.3 KiB
Python

import sys
import unittest
import pywintypes
import win32api
# A class that will never die vie refcounting, but will die via GC.
class Cycle:
def __init__(self, handle):
self.cycle = self
self.handle = handle
class PyHandleTestCase(unittest.TestCase):
def testCleanup1(self):
# We used to clobber all outstanding exceptions.
def f1(invalidate):
import win32event
h = win32event.CreateEvent(None, 0, 0, None)
if invalidate:
win32api.CloseHandle(int(h))
1 / 0
# If we invalidated, then the object destruction code will attempt
# to close an invalid handle. We don't wan't an exception in
# this case
def f2(invalidate):
"""This function should throw an IOError."""
try:
f1(invalidate)
except ZeroDivisionError as exc:
raise IOError("raise 2")
self.assertRaises(IOError, f2, False)
# Now do it again, but so the auto object destruction
# actually fails.
self.assertRaises(IOError, f2, True)
def testCleanup2(self):
# Cause an exception during object destruction.
# The worst this does is cause an ".XXX undetected error (why=3)"
# So avoiding that is the goal
import win32event
h = win32event.CreateEvent(None, 0, 0, None)
# Close the handle underneath the object.
win32api.CloseHandle(int(h))
# Object destructor runs with the implicit close failing
h = None
def testCleanup3(self):
# And again with a class - no __del__
import win32event
class Test:
def __init__(self):
self.h = win32event.CreateEvent(None, 0, 0, None)
win32api.CloseHandle(int(self.h))
t = Test()
t = None
def testCleanupGood(self):
# And check that normal error semantics *do* work.
import win32event
h = win32event.CreateEvent(None, 0, 0, None)
win32api.CloseHandle(int(h))
self.assertRaises(win32api.error, h.Close)
# A following Close is documented as working
h.Close()
def testInvalid(self):
h = pywintypes.HANDLE(-2)
try:
h.Close()
# Ideally, we'd:
# self.assertRaises(win32api.error, h.Close)
# and everywhere markh has tried, that would pass - but not on
# github automation, where the .Close apparently works fine.
# (same for -1. Using 0 appears to work fine everywhere)
# There still seems value in testing it though, so we just accept
# either working or failing.
except win32api.error:
pass
def testOtherHandle(self):
h = pywintypes.HANDLE(1)
h2 = pywintypes.HANDLE(h)
self.assertEqual(h, h2)
# but the above doesn't really test everything - we want a way to
# pass the handle directly into PyWinLong_AsVoidPtr. One way to
# to that is to abuse win32api.GetProcAddress() - the 2nd param
# is passed to PyWinLong_AsVoidPtr() if its not a string.
# passing a handle value of '1' should work - there is something
# at that ordinal
win32api.GetProcAddress(sys.dllhandle, h)
def testHandleInDict(self):
h = pywintypes.HANDLE(1)
d = dict(foo=h)
self.assertEqual(d["foo"], h)
def testHandleInDictThenInt(self):
h = pywintypes.HANDLE(1)
d = dict(foo=h)
self.assertEqual(d["foo"], 1)
def testHandleCompareNone(self):
h = pywintypes.HANDLE(1)
self.assertNotEqual(h, None)
self.assertNotEqual(None, h)
# ensure we use both __eq__ and __ne__ ops
self.assertFalse(h == None)
self.assertTrue(h != None)
def testHandleCompareInt(self):
h = pywintypes.HANDLE(1)
self.assertNotEqual(h, 0)
self.assertEqual(h, 1)
# ensure we use both __eq__ and __ne__ ops
self.assertTrue(h == 1)
self.assertTrue(1 == h)
self.assertFalse(h != 1)
self.assertFalse(1 != h)
self.assertFalse(h == 0)
self.assertFalse(0 == h)
self.assertTrue(h != 0)
self.assertTrue(0 != h)
def testHandleNonZero(self):
h = pywintypes.HANDLE(0)
self.assertFalse(h)
h = pywintypes.HANDLE(1)
self.assertTrue(h)
def testLong(self):
# sys.maxint+1 should always be a 'valid' handle, treated as an
# unsigned int, even though it is a long. Although pywin32 should not
# directly create such longs, using struct.unpack() with a P format
# may well return them. eg:
# >>> struct.unpack("P", struct.pack("P", -1))
# (4294967295L,)
try:
big = sys.maxsize
except AttributeError:
big = sys.maxint
pywintypes.HANDLE(big + 1)
def testGC(self):
# This used to provoke:
# Fatal Python error: unexpected exception during garbage collection
def make():
h = pywintypes.HANDLE(-2)
c = Cycle(h)
import gc
make()
gc.collect()
def testTypes(self):
self.assertRaises(TypeError, pywintypes.HANDLE, "foo")
self.assertRaises(TypeError, pywintypes.HANDLE, ())
if __name__ == "__main__":
unittest.main()