using System;
using System.Reflection;
using System.Collections;
namespace DotNetMock{
/// <summary>
/// Verifies objects that implement the IVerifiable interface.
/// </summary>
public sealed class Verifier
{
/// <summary>
/// Gets BindingFlags to determine which fields to call verify on.
/// </summary>
private static readonly BindingFlags _bindingFlags =
(
BindingFlags.DeclaredOnly
| BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.Static
);
/// <summary>
/// Keeps a list of objects that have been verified
/// </summary>
private static IList _verifiedObjects = new ArrayList();
#region Static
/// <summary>
/// Calls Verify() with the object and it's type.
/// </summary>
/// <param name="verifiableObject">Object to verify</param>
public static void Verify(Object verifiableObject)
{
if ( !_verifiedObjects.Contains( verifiableObject.GetHashCode() ) )
{
verify(verifiableObject, verifiableObject.GetType());
}
}
/// <summary>
/// Resets the list of verfied objects. Currently this needs to be run whenever two or more Verify() root
/// calls are made in a row. Otherwise, unpredictable results will occur. Typically, this should be called
/// in a Test fixtures TearDown method.
/// </summary>
public static void ResetVerifier()
{
_verifiedObjects.Clear();
}
/// <summary>
/// Iterates through an object until it's at the root type.
/// Then it collects all the fields according to the BindingFlags and calls verify() on
/// each field.
/// </summary>
/// <param name="verifiableObject">Object to verify.</param>
/// <param name="currentType">Current Type.</param>
private static void verify(Object verifiableObject, Type currentType)
{
if (isRootType(currentType))
{
return;
}
verify(verifiableObject, currentType.BaseType);
FieldInfo[] fields = currentType.GetFields(_bindingFlags);
foreach (FieldInfo field in fields)
{
verifyField(field, verifiableObject);
}
_verifiedObjects.Add( verifiableObject.GetHashCode() );
}
/// <summary>
/// Sets the object to the Verifiable interface, then calls verify().
/// </summary>
/// <param name="verifiableField">Current Field.</param>
/// <param name="verifiableObject">Current Object.</param>
private static void verifyField(FieldInfo verifiableField, Object verifiableObject)
{
Object fieldValue = verifiableField.GetValue(verifiableObject);
IVerifiable aVerifiable;
if ((aVerifiable = fieldValue as IVerifiable) != null)
{
if ( ! aVerifiable.IsVerified )
{
aVerifiable.Verify();
}
}
}
/// <summary>
/// Determines if the given type is System.Object.
/// </summary>
/// <param name="aType">Type to use.</param>
/// <returns>True/False.</returns>
private static bool isRootType(Type aType)
{
return (typeof(Object).Equals(aType));
}
#endregion
}
}
|