2 // System.Runtime.InteropServices.SafeHandle Test Cases
5 // Miguel de Icaza (miguel@novell.com)
7 // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
11 using System.Runtime.InteropServices;
12 using System.Security;
13 using Microsoft.Win32.SafeHandles;
15 namespace MonoTests.System.Runtime.InteropServices
18 public class SafeHandleTest
21 // This mimics SafeFileHandle, but does not actually own a handle
22 // We use this to test ownership and dispose exceptions.
24 public class FakeSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
26 public bool released = false;
27 public bool disposed = false;
29 public FakeSafeHandle (): base (true)
33 public FakeSafeHandle (bool ownership) : base (ownership)
37 public void ChangeHandle (IntPtr hnd)
42 protected override bool ReleaseHandle ()
48 protected override void Dispose (bool manual)
51 base.Dispose (manual);
56 [ExpectedException (typeof (ObjectDisposedException))]
57 public void BadDispose1 ()
59 FakeSafeHandle sf = new FakeSafeHandle ();
61 sf.DangerousRelease ();
62 sf.DangerousRelease ();
66 [ExpectedException (typeof (ObjectDisposedException))]
67 public void BadDispose2 ()
69 FakeSafeHandle sf = new FakeSafeHandle ();
72 sf.DangerousRelease ();
76 [ExpectedException (typeof (ObjectDisposedException))]
77 public void BadDispose3 ()
79 FakeSafeHandle sf = new FakeSafeHandle ();
82 sf.DangerousRelease ();
86 public void MultipleDisposes ()
88 FakeSafeHandle sf = new FakeSafeHandle ();
96 public void CloseWillDispose ()
98 FakeSafeHandle sf = new FakeSafeHandle ();
101 Assert.IsTrue (sf.disposed, "disposed");
105 public void GoodDispose ()
107 int dummyHandle = 0xDEAD;
108 FakeSafeHandle sf = new FakeSafeHandle ();
109 sf.ChangeHandle (new IntPtr (dummyHandle));
110 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
112 sf.DangerousRelease ();
117 } catch (ObjectDisposedException) {
123 } catch (ObjectDisposedException) {
126 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
127 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
128 //Handle was closed properly.
129 Assert.IsTrue (sf.released, "released");
130 Assert.IsTrue (sf.IsClosed, "closed");
131 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
132 Assert.IsFalse (sf.IsInvalid, "invalid");
136 public void SetHandleAsInvalid ()
138 int dummyHandle = 0xDEAD;
139 FakeSafeHandle sf = new FakeSafeHandle ();
141 sf.ChangeHandle (new IntPtr (dummyHandle));
142 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
144 sf.SetHandleAsInvalid();
146 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
147 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
148 //Released == false since handle was not released, Set Invalid was called before it could be released.
149 Assert.IsFalse (sf.released, "released");
150 //IsClosed == true since handle is pointing to a disposed or invalid object.
151 Assert.IsTrue (sf.IsClosed, "closed");
152 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
153 Assert.IsFalse (sf.IsInvalid, "invalid");
157 public void SetInvalidDispose ()
159 int dummyHandle = 0xDEAD;
160 FakeSafeHandle sf = new FakeSafeHandle (true);
162 sf.ChangeHandle (new IntPtr (dummyHandle));
163 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
165 sf.SetHandleAsInvalid();
168 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
169 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
170 //Released == false since handle was not released, Set Invalid was called before it could be released.
171 Assert.IsFalse (sf.released, "released");
172 //IsClosed == true since handle is pointing to a disposed or invalid object.
173 Assert.IsTrue (sf.IsClosed, "closed");
174 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
175 Assert.IsFalse (sf.IsInvalid, "invalid");
179 public void SetInvalidRelease1 ()
181 FakeSafeHandle sf = new FakeSafeHandle (true);
183 bool success = false;
184 sf.DangerousAddRef(ref success);
185 Assert.IsTrue (success, "dar");
187 sf.SetHandleAsInvalid();
189 Assert.IsFalse (sf.released, "released");
190 Assert.IsTrue (sf.IsClosed, "closed");
192 //Allow remaining refs to be released after SetHandleAsInvalid
193 sf.DangerousRelease ();
194 sf.DangerousRelease ();
196 Assert.IsFalse (sf.released, "released");
197 Assert.IsTrue (sf.IsClosed, "closed");
201 [ExpectedException (typeof (ObjectDisposedException))]
202 public void SetInvalidRelease2 ()
204 FakeSafeHandle sf = new FakeSafeHandle (true);
206 bool success = false;
207 sf.DangerousAddRef(ref success);
208 Assert.IsTrue (success, "dar");
210 sf.SetHandleAsInvalid();
211 sf.DangerousRelease ();
212 sf.DangerousRelease ();
214 //This release need to throw ObjectDisposedException.
215 //No more ref to release.
216 sf.DangerousRelease ();
220 public void ReleaseAfterDispose1 ()
222 int dummyHandle = 0xDEAD;
223 FakeSafeHandle sf = new FakeSafeHandle (true);
224 sf.ChangeHandle (new IntPtr (dummyHandle));
225 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
227 bool success = false;
228 sf.DangerousAddRef(ref success);
229 Assert.IsTrue (success, "dar");
232 //Still one ref left.
233 Assert.IsFalse (sf.released, "released");
234 Assert.IsFalse (sf.IsClosed, "closed");
236 sf.DangerousRelease ();
237 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
238 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
239 //Handle was closed properly.
240 Assert.IsTrue (sf.released, "released");
241 Assert.IsTrue (sf.IsClosed, "closed");
242 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
243 Assert.IsFalse (sf.IsInvalid, "invalid");
247 [ExpectedException (typeof (ObjectDisposedException))]
248 public void ReleaseAfterDispose2 ()
250 FakeSafeHandle sf = new FakeSafeHandle (true);
252 bool success = false;
253 sf.DangerousAddRef(ref success);
254 Assert.IsTrue (success, "dar");
258 sf.DangerousRelease ();
260 //Second release need to throw ObjectDisposedException.
261 //No more ref to release.
262 sf.DangerousRelease ();
266 public void NoReleaseUnowned ()
268 FakeSafeHandle sf = new FakeSafeHandle (false);
271 Assert.IsFalse (sf.released, "r1");
272 Assert.IsTrue (sf.IsClosed, "c1");
274 sf = new FakeSafeHandle (false);
275 sf.DangerousRelease ();
276 Assert.IsFalse (sf.released, "r2");
277 Assert.IsTrue (sf.IsClosed, "c2");
279 sf = new FakeSafeHandle (false);
280 ((IDisposable) sf).Dispose ();
281 Assert.IsFalse (sf.released, "r3");
282 Assert.IsTrue (sf.IsClosed, "c3");
286 // This test does a DangerousAddRef on a new instance
287 // of a custom user Safe Handle, and it just happens
288 // that the default value for the handle is an invalid
291 // .NET does not throw an exception in this case, so
292 // we should not either
295 public void DangerousAddRefOnNewInstance ()
297 FakeSafeHandle sf = new FakeSafeHandle ();
298 sf.ChangeHandle (IntPtr.Zero);
299 Assert.IsTrue (sf.IsInvalid, "invalid");
301 bool success = false;
302 sf.DangerousAddRef (ref success);
303 Assert.IsTrue (success, "daroni");