449 lines
14 KiB
C#
449 lines
14 KiB
C#
#region License
|
|
|
|
/*
|
|
* Copyright © 2002-2005 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 Spring
|
|
{
|
|
/// <summary>
|
|
/// Tests the various exception classes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Shamelessly lifted from the NAnt test suite.
|
|
/// </para>
|
|
/// </remarks>
|
|
public abstract class ExceptionsTest : StandardsComplianceTest
|
|
{
|
|
// sorry folks, but this is really a special case - default ctor policy doesn't apply here
|
|
private bool ExcludeFromConstructorPolicyCheck(Type t)
|
|
{
|
|
//TODO: uncomment when making SyntaxErrorException public:
|
|
if (t.FullName == "Spring.Expressions.SyntaxErrorException") return true;
|
|
return false;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (!ExcludeFromConstructorPolicyCheck(t))
|
|
{
|
|
// 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
|
|
&& !ExcludeFromConstructorPolicyCheck(t))
|
|
{
|
|
CheckInstantiation(t);
|
|
}
|
|
}
|
|
|
|
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
|
|
} |