#region License
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using NUnit.Framework;
#endregion
namespace Common{
/// <summary>
/// Tests the various exception classes.
/// </summary>
/// <remarks>
/// <para>
/// Shamelessly lifted from the NAnt test suite.
/// </para>
/// </remarks>
/// <author>Rick Evans</author>
/// <version>$Id:$</version>
public abstract class ExceptionsTest : StandardsComplianceTest
{
protected ExceptionsTest()
{
CheckedType = typeof (Exception);
}
#region Tests
[Test]
public void TestStandardsCompliance()
{
ProcessAssembly(AssemblyToCheck);
}
[Test]
public void TestThisTest()
{
ProcessAssembly(Assembly.GetAssembly(GetType()));
}
#endregion
#region Methods
protected override void CheckStandardsCompliance(Assembly assembly, Type t)
{
// check to see that the exception is correctly named, with "Exception" at the end
bool nameIsValid = t.Name.EndsWith("Exception");
Assert.IsTrue(nameIsValid, t.Name + " class name must end with Exception.");
if (t.IsAbstract)
{
return;
}
// Does the exception have the 3 standard constructors?
// Default constructor
CheckPublicConstructor(t, "()");
// Constructor with a single string parameter
CheckPublicConstructor(t, "(string message)", typeof (String));
// Constructor with a string and an inner exception
CheckPublicConstructor(t, "(string message, Exception inner)",
typeof (String), typeof (Exception));
// check to see if the serialization constructor is present
// if exception is sealed, constructor should be private
// if exception is not sealed, constructor should be protected
if (t.IsSealed)
{
// check to see if the private serialization constructor is present...
CheckPrivateConstructor(t, "(SerializationInfo info, StreamingContext context)",
typeof (SerializationInfo),
typeof (StreamingContext));
}
else
{
// check to see if the protected serialization constructor is present...
CheckProtectedConstructor(t, "(SerializationInfo info, StreamingContext context)",
typeof (SerializationInfo),
typeof (StreamingContext));
}
// check to see if the type is marked as serializable
Assert.IsTrue(t.IsSerializable, t.Name + " is not serializable, missing [Serializable]?");
// check to see if there are any public fields. These should be properties instead...
FieldInfo[] publicFields =
t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
if (publicFields.Length != 0)
{
foreach (FieldInfo fieldInfo in publicFields)
{
Assert.Fail(t.Name + "." + fieldInfo.Name +
" is a public field, should be exposed through property instead.");
}
}
// If this exception has any fields, check to make sure it has a
// version of GetObjectData. If not, it does't serialize those fields.
FieldInfo[] fields =
t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance);
if (fields.Length != 0)
{
if (
t.GetMethod("GetObjectData", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance) ==
null)
{
Assert.Fail(t.Name + " does not implement GetObjectData but has private fields.");
}
}
if (!t.IsAbstract)
{
CheckInstantiation(t);
}
}
/// <summary>
/// Checks the public constructor.
/// </summary>
/// <param name="t">The type</param>
/// <param name="description">The description.</param>
/// <param name="parameters">The parameters.</param>
private void CheckPublicConstructor(Type t, string description, params Type[] parameters)
{
// locate constructor
ConstructorInfo ci =
t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters,
null);
// fail if constructor does not exist
Assert.IsNotNull(ci, t.Name + description + " is a required constructor.");
// fail if constructor is private
Assert.IsFalse(ci.IsPrivate, t.Name + description + " is private, must be public.");
// fail if constructor is protected
Assert.IsFalse(ci.IsFamily, t.Name + description + " is internal, must be public.");
// fail if constructor is internal
Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be public.");
// fail if constructor is protected internal
Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be public.");
// sanity check to make sure the constructor is public
Assert.IsTrue(ci.IsPublic, t.Name + description + " is not public, must be public.");
}
private void CheckProtectedConstructor(Type t, string description, params Type[] parameters)
{
// locate constructor
ConstructorInfo ci =
t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters,
null);
// fail if constructor does not exist
Assert.IsNotNull(ci, t.Name + description + " is a required constructor.");
// fail if constructor is public
Assert.IsFalse(ci.IsPublic, t.Name + description + " is public, must be protected.");
// fail if constructor is private
Assert.IsFalse(ci.IsPrivate, t.Name + description + " is private, must be public or protected.");
// fail if constructor is internal
Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be protected.");
// fail if constructor is protected internal
Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be protected.");
// sanity check to make sure the constructor is protected
Assert.IsTrue(ci.IsFamily, t.Name + description + " is not protected, must be protected.");
}
private void CheckPrivateConstructor(Type t, string description, params Type[] parameters)
{
// locate constructor
ConstructorInfo ci =
t.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameters,
null);
// fail if constructor does not exist
Assert.IsNotNull(ci, t.Name + description + " is a required constructor.");
// fail if constructor is public
Assert.IsFalse(ci.IsPublic, t.Name + description + " is public, must be private.");
// fail if constructor is protected
Assert.IsFalse(ci.IsFamily, t.Name + description + " is protected, must be private.");
// fail if constructor is internal
Assert.IsFalse(ci.IsAssembly, t.Name + description + " is internal, must be private.");
// fail if constructor is protected internal
Assert.IsFalse(ci.IsFamilyOrAssembly, t.Name + description + " is protected internal, must be private.");
// sanity check to make sure the constructor is private
Assert.IsTrue(ci.IsPrivate, t.Name + description + " is not private, must be private.");
}
/// <summary>
/// If we've got here, then the standards compliance tests have passed...
/// </summary>
/// <param name="t">The exception type being tested.</param>
private void CheckInstantiation(Type t)
{
// attempt to instantiate the 3 standard ctors...
ConstructorInfo ctor = t.GetConstructor(Type.EmptyTypes);
try
{
ctor.Invoke(null);
}
catch (Exception ex)
{
Assert.Fail("Ctor () for '" + t.Name + "' threw an exception : " + ex.Message);
}
ctor = t.GetConstructor(new Type[] {typeof (string)});
try
{
Exception ex = (Exception) ctor.Invoke(new object[] {"My Fingers Turn To Fists"});
Assert.IsNotNull(ex.Message, t.Name + "'s Message was null.");
}
catch (Exception ex)
{
Assert.Fail("Ctor (string) for '" + t.Name + "' threw an exception : " + ex.Message);
}
ctor = t.GetConstructor(new Type[] {typeof (string), typeof (Exception)});
try
{
Exception ex =
(Exception) ctor.Invoke(new object[] {"My Fingers Turn To Fists", new FormatException("Bing")});
Assert.IsNotNull(ex.Message, t.Name + "'s Message was null.");
Assert.IsNotNull(ex.InnerException, t.Name + "'s InnerException was null.");
Assert.AreEqual("Bing", ex.InnerException.Message);
}
catch (Exception ex)
{
Assert.Fail("Ctor (string, Exception) for '" + t.Name + "' threw an exception : " + ex.Message);
}
// test the serialization ctor
try
{
ctor = t.GetConstructor(new Type[] {typeof (string)});
Exception ex = (Exception) ctor.Invoke(new object[] {"HungerHurtsButStarvingWorks"});
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, ex);
ms.Seek(0, 0);
Exception inex = (Exception) bf.Deserialize(ms);
Assert.IsNotNull(inex);
}
catch (Exception ex)
{
Assert.Fail("Ctor (Serialization) for '" + t.Name + "' threw an exception : " + ex.Message);
}
}
#endregion
#region Properties
/// <summary>
/// We will test all of the exceptions in this assembly for their correctness.
/// </summary>
protected Assembly AssemblyToCheck
{
get { return _assemblyToCheck; }
set { _assemblyToCheck = value; }
}
#endregion
private Assembly _assemblyToCheck = null;
}
#region Inner Class : SimpleTestException
/// <summary>
/// Do nothing exception to verify that the exception tester
/// is working correctly.
/// </summary>
[Serializable]
public class SimpleTestException : ApplicationException
{
#region Public Instance Constructors
public SimpleTestException()
{
}
public SimpleTestException(string message) : base(message)
{
}
public SimpleTestException(string message, Exception inner)
: base(message, inner)
{
}
#endregion Public Instance Constructors
#region Protected Instance Constructors
// deserialization constructor
protected SimpleTestException(
SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endregion Protected Instance Constructors
}
#endregion
#region Inner Class : TestException
/// <summary>
/// Exception to verify that the exception tester is working correctly.
/// </summary>
[Serializable]
public class TestException : ApplicationException, ISerializable
{
#region Private Instance Fields
private int _value;
#endregion Private Instance Fields
#region Public Instance Constructors
public TestException()
{
}
public TestException(string message) : base(message)
{
}
public TestException(string message, Exception inner)
: base(message, inner)
{
}
// constructors that take the added value
public TestException(string message, int value) : base(message)
{
_value = value;
}
#endregion Public Instance Constructors
#region Protected Instance Constructors
// deserialization constructor
protected TestException(SerializationInfo info, StreamingContext context) : base(info, context)
{
_value = info.GetInt32("Value");
}
#endregion Protected Instance Constructors
#region Public Instance Properties
public int Value
{
get { return _value; }
}
#endregion Public Instance Properties
#region Override implementation of ApplicationException
// Called by the frameworks during serialization
// to fetch the data from an object.
public override void GetObjectData(
SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("Value", _value);
}
// overridden Message property. This will give the
// proper textual representation of the exception,
// with the added field value.
public override string Message
{
get
{
// NOTE: should be localized...
string s =
string.Format(
CultureInfo.InvariantCulture, "Value: {0}", _value);
return base.Message + Environment.NewLine + s;
}
}
#endregion Override implementation of ApplicationException
}
#endregion
#region Inner Class : SealedTestException
/// <summary>
/// Exception to verify that the exception tester is working on
/// sealed exception.
/// </summary>
[Serializable]
public sealed class SealedTestException : TestException
{
#region Public Instance Constructors
public SealedTestException()
{
}
public SealedTestException(string message) : base(message)
{
}
public SealedTestException(string message, Exception inner)
: base(message, inner)
{
}
// constructors that take the added value
public SealedTestException(string message, int value)
: base(message, value)
{
}
#endregion Public Instance Constructors
#region Private Instance Constructors
// deserialization constructor
private SealedTestException(
SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endregion Private Instance Constructors
}
#endregion
}
|