966bba02bb
Former-commit-id: bb0468d0f257ff100aa895eb5fe583fb5dfbf900
323 lines
8.0 KiB
C#
323 lines
8.0 KiB
C#
//
|
|
// System.Runtime.InteropServices.SafeHandle Test Cases
|
|
//
|
|
// Authors:
|
|
// Miguel de Icaza (miguel@novell.com)
|
|
//
|
|
// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
|
|
//
|
|
using NUnit.Framework;
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
using Microsoft.Win32.SafeHandles;
|
|
|
|
namespace MonoTests.System.Runtime.InteropServices
|
|
{
|
|
[TestFixture]
|
|
public class SafeHandleTest
|
|
{
|
|
//
|
|
// This mimics SafeFileHandle, but does not actually own a handle
|
|
// We use this to test ownership and dispose exceptions.
|
|
//
|
|
public class FakeSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
|
|
{
|
|
public bool released = false;
|
|
public bool disposed = false;
|
|
|
|
public FakeSafeHandle (): base (true)
|
|
{
|
|
}
|
|
|
|
public FakeSafeHandle (bool ownership) : base (ownership)
|
|
{
|
|
}
|
|
|
|
public void ChangeHandle (IntPtr hnd)
|
|
{
|
|
this.handle = hnd;
|
|
}
|
|
|
|
protected override bool ReleaseHandle ()
|
|
{
|
|
released = true;
|
|
return true;
|
|
}
|
|
|
|
protected override void Dispose (bool manual)
|
|
{
|
|
disposed = true;
|
|
base.Dispose (manual);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void SimpleDispose ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
sf.Dispose ();
|
|
}
|
|
|
|
[Test]
|
|
public void BadDispose1 ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
|
|
sf.DangerousRelease ();
|
|
|
|
try {
|
|
sf.DangerousRelease ();
|
|
Assert.Fail ("#1");
|
|
} catch (ObjectDisposedException) {
|
|
}
|
|
|
|
GC.SuppressFinalize (sf);
|
|
}
|
|
|
|
[Test]
|
|
[ExpectedException (typeof (ObjectDisposedException))]
|
|
public void BadDispose2 ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
|
|
sf.Close ();
|
|
sf.DangerousRelease ();
|
|
}
|
|
|
|
[Test]
|
|
[ExpectedException (typeof (ObjectDisposedException))]
|
|
public void BadDispose3 ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
|
|
sf.Dispose ();
|
|
sf.DangerousRelease ();
|
|
}
|
|
|
|
[Test]
|
|
public void MultipleDisposes ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
|
|
sf.Dispose ();
|
|
sf.Dispose ();
|
|
sf.Dispose ();
|
|
}
|
|
|
|
[Test]
|
|
public void CloseWillDispose ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
|
|
sf.Close ();
|
|
Assert.IsTrue (sf.disposed, "disposed");
|
|
}
|
|
|
|
[Test]
|
|
public void GoodDispose ()
|
|
{
|
|
int dummyHandle = 0xDEAD;
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
sf.ChangeHandle (new IntPtr (dummyHandle));
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
|
|
sf.DangerousRelease ();
|
|
|
|
try {
|
|
sf.Close ();
|
|
Assert.Fail ("#1");
|
|
} catch (ObjectDisposedException) {
|
|
}
|
|
|
|
try {
|
|
sf.Dispose ();
|
|
Assert.Fail ("#2");
|
|
} catch (ObjectDisposedException) {
|
|
}
|
|
|
|
//In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
//Handle was closed properly.
|
|
Assert.IsTrue (sf.released, "released");
|
|
Assert.IsTrue (sf.IsClosed, "closed");
|
|
//Handle value is not changed, so the value itself is still valid (not 0 or -1)
|
|
Assert.IsFalse (sf.IsInvalid, "invalid");
|
|
|
|
GC.SuppressFinalize (sf);
|
|
}
|
|
|
|
[Test]
|
|
public void SetHandleAsInvalid ()
|
|
{
|
|
int dummyHandle = 0xDEAD;
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
|
|
sf.ChangeHandle (new IntPtr (dummyHandle));
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
|
|
sf.SetHandleAsInvalid();
|
|
|
|
//In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
//Released == false since handle was not released, Set Invalid was called before it could be released.
|
|
Assert.IsFalse (sf.released, "released");
|
|
//IsClosed == true since handle is pointing to a disposed or invalid object.
|
|
Assert.IsTrue (sf.IsClosed, "closed");
|
|
//Handle value is not changed, so the value itself is still valid (not 0 or -1)
|
|
Assert.IsFalse (sf.IsInvalid, "invalid");
|
|
}
|
|
|
|
[Test]
|
|
public void SetInvalidDispose ()
|
|
{
|
|
int dummyHandle = 0xDEAD;
|
|
FakeSafeHandle sf = new FakeSafeHandle (true);
|
|
|
|
sf.ChangeHandle (new IntPtr (dummyHandle));
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
|
|
sf.SetHandleAsInvalid();
|
|
sf.Dispose ();
|
|
|
|
//In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
//Released == false since handle was not released, Set Invalid was called before it could be released.
|
|
Assert.IsFalse (sf.released, "released");
|
|
//IsClosed == true since handle is pointing to a disposed or invalid object.
|
|
Assert.IsTrue (sf.IsClosed, "closed");
|
|
//Handle value is not changed, so the value itself is still valid (not 0 or -1)
|
|
Assert.IsFalse (sf.IsInvalid, "invalid");
|
|
}
|
|
|
|
[Test]
|
|
public void SetInvalidRelease1 ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle (true);
|
|
|
|
bool success = false;
|
|
sf.DangerousAddRef(ref success);
|
|
Assert.IsTrue (success, "dar");
|
|
|
|
sf.SetHandleAsInvalid();
|
|
|
|
Assert.IsFalse (sf.released, "released");
|
|
Assert.IsTrue (sf.IsClosed, "closed");
|
|
|
|
//Allow remaining refs to be released after SetHandleAsInvalid
|
|
sf.DangerousRelease ();
|
|
sf.DangerousRelease ();
|
|
|
|
Assert.IsFalse (sf.released, "released");
|
|
Assert.IsTrue (sf.IsClosed, "closed");
|
|
}
|
|
|
|
[Test]
|
|
[ExpectedException (typeof (ObjectDisposedException))]
|
|
public void SetInvalidRelease2 ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle (true);
|
|
|
|
bool success = false;
|
|
sf.DangerousAddRef(ref success);
|
|
Assert.IsTrue (success, "dar");
|
|
|
|
sf.SetHandleAsInvalid();
|
|
sf.DangerousRelease ();
|
|
sf.DangerousRelease ();
|
|
|
|
//This release need to throw ObjectDisposedException.
|
|
//No more ref to release.
|
|
sf.DangerousRelease ();
|
|
}
|
|
|
|
[Test]
|
|
public void ReleaseAfterDispose1 ()
|
|
{
|
|
int dummyHandle = 0xDEAD;
|
|
FakeSafeHandle sf = new FakeSafeHandle (true);
|
|
sf.ChangeHandle (new IntPtr (dummyHandle));
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
|
|
bool success = false;
|
|
sf.DangerousAddRef(ref success);
|
|
Assert.IsTrue (success, "dar");
|
|
|
|
sf.Dispose ();
|
|
//Still one ref left.
|
|
Assert.IsFalse (sf.released, "released");
|
|
Assert.IsFalse (sf.IsClosed, "closed");
|
|
|
|
sf.DangerousRelease ();
|
|
//In Ms.Net SafeHandle does not change the value of the handle after being SetInvalid or Disposed.
|
|
Assert.AreEqual ((int)sf.DangerousGetHandle(), dummyHandle, "handle");
|
|
//Handle was closed properly.
|
|
Assert.IsTrue (sf.released, "released");
|
|
Assert.IsTrue (sf.IsClosed, "closed");
|
|
//Handle value is not changed, so the value itself is still valid (not 0 or -1)
|
|
Assert.IsFalse (sf.IsInvalid, "invalid");
|
|
}
|
|
|
|
[Test]
|
|
[ExpectedException (typeof (ObjectDisposedException))]
|
|
public void ReleaseAfterDispose2 ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle (true);
|
|
|
|
bool success = false;
|
|
sf.DangerousAddRef(ref success);
|
|
Assert.IsTrue (success, "dar");
|
|
|
|
sf.Dispose ();
|
|
|
|
sf.DangerousRelease ();
|
|
|
|
//Second release need to throw ObjectDisposedException.
|
|
//No more ref to release.
|
|
sf.DangerousRelease ();
|
|
}
|
|
|
|
[Test]
|
|
public void NoReleaseUnowned ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle (false);
|
|
|
|
sf.Close ();
|
|
Assert.IsFalse (sf.released, "r1");
|
|
Assert.IsTrue (sf.IsClosed, "c1");
|
|
|
|
sf = new FakeSafeHandle (false);
|
|
sf.DangerousRelease ();
|
|
Assert.IsFalse (sf.released, "r2");
|
|
Assert.IsTrue (sf.IsClosed, "c2");
|
|
|
|
sf = new FakeSafeHandle (false);
|
|
((IDisposable) sf).Dispose ();
|
|
Assert.IsFalse (sf.released, "r3");
|
|
Assert.IsTrue (sf.IsClosed, "c3");
|
|
}
|
|
|
|
//
|
|
// This test does a DangerousAddRef on a new instance
|
|
// of a custom user Safe Handle, and it just happens
|
|
// that the default value for the handle is an invalid
|
|
// handle.
|
|
//
|
|
// .NET does not throw an exception in this case, so
|
|
// we should not either
|
|
//
|
|
[Test]
|
|
public void DangerousAddRefOnNewInstance ()
|
|
{
|
|
FakeSafeHandle sf = new FakeSafeHandle ();
|
|
sf.ChangeHandle (IntPtr.Zero);
|
|
Assert.IsTrue (sf.IsInvalid, "invalid");
|
|
|
|
bool success = false;
|
|
sf.DangerousAddRef (ref success);
|
|
Assert.IsTrue (success, "daroni");
|
|
}
|
|
}
|
|
}
|
|
|