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)
52 // Bombs on Android (ObjectDisposedException)
53 base.Dispose (manual);
59 public void SimpleDispose ()
61 FakeSafeHandle sf = new FakeSafeHandle ();
66 public void BadDispose1 ()
68 FakeSafeHandle sf = new FakeSafeHandle ();
70 sf.DangerousRelease ();
73 sf.DangerousRelease ();
75 } catch (ObjectDisposedException) {
78 GC.SuppressFinalize (sf);
82 [ExpectedException (typeof (ObjectDisposedException))]
83 [Category ("AndroidNotWorking")] // Because of the FakeSafeHandle.Dispose issue
84 public void BadDispose2 ()
86 FakeSafeHandle sf = new FakeSafeHandle ();
89 sf.DangerousRelease ();
93 [ExpectedException (typeof (ObjectDisposedException))]
94 [Category ("AndroidNotWorking")] // Because of the FakeSafeHandle.Dispose issue
95 public void BadDispose3 ()
97 FakeSafeHandle sf = new FakeSafeHandle ();
100 sf.DangerousRelease ();
104 public void MultipleDisposes ()
106 FakeSafeHandle sf = new FakeSafeHandle ();
114 public void CloseWillDispose ()
116 FakeSafeHandle sf = new FakeSafeHandle ();
119 Assert.IsTrue (sf.disposed, "disposed");
123 [Category ("AndroidNotWorking")] // Because of the FakeSafeHandle.Dispose issue
124 public void GoodDispose ()
126 int dummyHandle = 0xDEAD;
127 FakeSafeHandle sf = new FakeSafeHandle ();
128 sf.ChangeHandle (new IntPtr (dummyHandle));
129 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
131 sf.DangerousRelease ();
136 } catch (ObjectDisposedException) {
142 } catch (ObjectDisposedException) {
145 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
146 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
147 //Handle was closed properly.
148 Assert.IsTrue (sf.released, "released");
149 Assert.IsTrue (sf.IsClosed, "closed");
150 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
151 Assert.IsFalse (sf.IsInvalid, "invalid");
153 GC.SuppressFinalize (sf);
157 public void SetHandleAsInvalid ()
159 int dummyHandle = 0xDEAD;
160 FakeSafeHandle sf = new FakeSafeHandle ();
162 sf.ChangeHandle (new IntPtr (dummyHandle));
163 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
165 sf.SetHandleAsInvalid();
167 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
168 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
169 //Released == false since handle was not released, Set Invalid was called before it could be released.
170 Assert.IsFalse (sf.released, "released");
171 //IsClosed == true since handle is pointing to a disposed or invalid object.
172 Assert.IsTrue (sf.IsClosed, "closed");
173 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
174 Assert.IsFalse (sf.IsInvalid, "invalid");
178 public void SetInvalidDispose ()
180 int dummyHandle = 0xDEAD;
181 FakeSafeHandle sf = new FakeSafeHandle (true);
183 sf.ChangeHandle (new IntPtr (dummyHandle));
184 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
186 sf.SetHandleAsInvalid();
189 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
190 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
191 //Released == false since handle was not released, Set Invalid was called before it could be released.
192 Assert.IsFalse (sf.released, "released");
193 //IsClosed == true since handle is pointing to a disposed or invalid object.
194 Assert.IsTrue (sf.IsClosed, "closed");
195 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
196 Assert.IsFalse (sf.IsInvalid, "invalid");
200 public void SetInvalidRelease1 ()
202 FakeSafeHandle sf = new FakeSafeHandle (true);
204 bool success = false;
205 sf.DangerousAddRef(ref success);
206 Assert.IsTrue (success, "dar");
208 sf.SetHandleAsInvalid();
210 Assert.IsFalse (sf.released, "released");
211 Assert.IsTrue (sf.IsClosed, "closed");
213 //Allow remaining refs to be released after SetHandleAsInvalid
214 sf.DangerousRelease ();
215 sf.DangerousRelease ();
217 Assert.IsFalse (sf.released, "released");
218 Assert.IsTrue (sf.IsClosed, "closed");
222 [ExpectedException (typeof (ObjectDisposedException))]
223 public void SetInvalidRelease2 ()
225 FakeSafeHandle sf = new FakeSafeHandle (true);
227 bool success = false;
228 sf.DangerousAddRef(ref success);
229 Assert.IsTrue (success, "dar");
231 sf.SetHandleAsInvalid();
232 sf.DangerousRelease ();
233 sf.DangerousRelease ();
235 //This release need to throw ObjectDisposedException.
236 //No more ref to release.
237 sf.DangerousRelease ();
241 [Category ("AndroidNotWorking")] // Because of the FakeSafeHandle.Dispose issue
242 public void ReleaseAfterDispose1 ()
244 int dummyHandle = 0xDEAD;
245 FakeSafeHandle sf = new FakeSafeHandle (true);
246 sf.ChangeHandle (new IntPtr (dummyHandle));
247 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
249 bool success = false;
250 sf.DangerousAddRef(ref success);
251 Assert.IsTrue (success, "dar");
254 //Still one ref left.
255 Assert.IsFalse (sf.released, "released");
256 Assert.IsFalse (sf.IsClosed, "closed");
258 sf.DangerousRelease ();
259 //In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
260 Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
261 //Handle was closed properly.
262 Assert.IsTrue (sf.released, "released");
263 Assert.IsTrue (sf.IsClosed, "closed");
264 //Handle value is not changed, so the value itself is still valid (not 0 or -1)
265 Assert.IsFalse (sf.IsInvalid, "invalid");
269 [ExpectedException (typeof (ObjectDisposedException))]
270 [Category ("AndroidNotWorking")] // Because of the FakeSafeHandle.Dispose issue
271 public void ReleaseAfterDispose2 ()
273 FakeSafeHandle sf = new FakeSafeHandle (true);
275 bool success = false;
276 sf.DangerousAddRef(ref success);
277 Assert.IsTrue (success, "dar");
281 sf.DangerousRelease ();
283 //Second release need to throw ObjectDisposedException.
284 //No more ref to release.
285 sf.DangerousRelease ();
289 [Category ("AndroidNotWorking")] // Not until Dispose runtime crasher in FakeSafeHandle is fixed
290 public void NoReleaseUnowned ()
292 FakeSafeHandle sf = new FakeSafeHandle (false);
295 Assert.IsFalse (sf.released, "r1");
296 Assert.IsTrue (sf.IsClosed, "c1");
298 sf = new FakeSafeHandle (false);
299 sf.DangerousRelease ();
300 Assert.IsFalse (sf.released, "r2");
301 Assert.IsTrue (sf.IsClosed, "c2");
303 sf = new FakeSafeHandle (false);
304 ((IDisposable) sf).Dispose ();
305 Assert.IsFalse (sf.released, "r3");
306 Assert.IsTrue (sf.IsClosed, "c3");
310 // This test does a DangerousAddRef on a new instance
311 // of a custom user Safe Handle, and it just happens
312 // that the default value for the handle is an invalid
315 // .NET does not throw an exception in this case, so
316 // we should not either
319 public void DangerousAddRefOnNewInstance ()
321 FakeSafeHandle sf = new FakeSafeHandle ();
322 sf.ChangeHandle (IntPtr.Zero);
323 Assert.IsTrue (sf.IsInvalid, "invalid");
325 bool success = false;
326 sf.DangerousAddRef (ref success);
327 Assert.IsTrue (success, "daroni");