// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// -----------------------------------------------------------------------
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Runtime.Serialization;
namespace System.UnitTesting
{
public static class ExceptionAssert
{
// NOTE: To catch state corrupting exceptions, it by design that
// the ThrowsXXX methods retry by default. To prevent this in a
// test, simply use one of the overloads that takes a RetryMode.
///
/// Verifies that the exception has the default message generated by the base Exception class.
///
public static void HasDefaultMessage(Exception exception)
{
Assert.IsNotNull(exception);
// Exception of type '[typename]' was thrown
StringAssert.Contains(exception.Message, exception.GetType().FullName);
}
///
/// Verifies that the specified action throws a SerializationException.
///
public static SerializationException ThrowsSerialization(string memberName, Action action)
{
var exception = Throws(RetryMode.Retry, action, (actual, retryCount) =>
{
AssertSerializationMemberName(memberName, actual, retryCount);
});
return exception;
}
///
/// Verifies that the specified action throws an ObjectDisposedException.
///
public static ObjectDisposedException ThrowsDisposed(object instance, Action action)
{
var exception = Throws(RetryMode.Retry, action, (actual, retryCount) =>
{
AssertObjectDisposed(instance, actual, retryCount);
});
return exception;
}
///
/// Verifies that the specified action throws an ArgumentNullException.
///
public static ArgumentNullException ThrowsArgumentNull(string parameterName, Action action)
{
return ThrowsArgument(parameterName, action);
}
///
/// Verifies that the specified action throws an ArgumentException.
///
public static ArgumentException ThrowsArgument(string parameterName, Action action)
{
return ThrowsArgument(parameterName, action);
}
///
/// Verifies that the specified action throws an ArgumentException of type .
///
public static T ThrowsArgument(string parameterName, Action action)
where T : ArgumentException
{
var exception = Throws(RetryMode.Retry, action, (actual, retryCount) =>
{
AssertSameParameterName(parameterName, actual, retryCount);
});
return exception;
}
///
/// Verifies that the specified action throws an exception of type ,
/// with the specified inner exception of type .
///
public static T Throws(Action action)
where T : Exception
where TInner : Exception
{
return Throws(RetryMode.Retry, action);
}
///
/// Verifies that the specified action throws an exception of type ,
/// with the specified inner exception of type , and indicating
/// whether to retry.
///
public static T Throws(RetryMode retry, Action action)
where T : Exception
where TInner : Exception
{
return Throws(retry, action, (Action)null);
}
///
/// Verifies that the specified action throws an exception of type ,
/// with the specified inner exception of type , indicating
/// whether to retry and running the specified validator.
///
public static T Throws(RetryMode retry, Action action, Action validator)
where T : Exception
where TInner : Exception
{
var exception = Throws(retry, action, (actual, retryCount) =>
{
AssertIsExactInstanceOfInner(typeof(TInner), actual, retryCount);
if (validator != null)
{
validator(actual, retryCount);
}
});
return exception;
}
///
/// Verifies that the specified action throws an exception of type ,
/// with the specified inner exception.
///
public static T Throws(Exception innerException, Action action)
where T : Exception
{
return Throws(innerException, RetryMode.Retry, action, (Action)null);
}
///
/// Verifies that the specified action throws an exception of type ,
/// with the specified inner exception, and indicating whether to retry.
///
public static T Throws(Exception innerException, RetryMode retry, Action action)
where T : Exception
{
return Throws(innerException, RetryMode.Retry, action, (Action)null);
}
///
/// Verifies that the specified action throws an exception of type ,
/// with the specified inner exception, indicating whether to retry and running the
/// specified validator.
///
public static T Throws(Exception innerException, RetryMode retry, Action action, Action validator)
where T : Exception
{
T exception = Throws(retry, action, (actual, retryCount) =>
{
AssertSameInner(innerException, actual, retryCount);
if (validator != null)
{
validator(actual, retryCount);
}
});
return exception;
}
///
/// Verifies that the specified action throws an exception of type .
///
public static T Throws(Action action)
where T : Exception
{
return Throws(RetryMode.Retry, action, (Action)null);
}
///
/// Verifies that the specified action throws an exception of type ,
/// indicating whether to retry.
///
public static T Throws(RetryMode retry, Action action)
where T : Exception
{
return Throws(retry, action, (Action)null);
}
///
/// Verifies that the specified action throws an exception of type ,
/// indicating whether to retry and running the specified validator.
///
public static T Throws(RetryMode retry, Action action, Action validator)
where T : Exception
{
var exception = (T)Run(retry, action, (actual, retryCount) =>
{
AssertIsExactInstanceOf(typeof(T), actual, retryCount);
if (validator != null)
{
validator((T)actual, retryCount);
}
});
return exception;
}
///
/// Verifies that the specified action throws the specified exception.
///
public static void Throws(Exception expected, Action action)
{
Throws(expected, RetryMode.Retry, action);
}
///
/// Verifies that the specified action throws the specified exception,
/// indicating whether to retry.
///
public static void Throws(Exception expected, RetryMode retry, Action action)
{
Throws(expected, retry, action, (Action)null);
}
///
/// Verifies that the specified action throws the specified exception,
/// indicating whether to retry and running the specified validator.
///
public static void Throws(Exception expected, RetryMode retry, Action action, Action validator)
{
Run(retry, action, (actual, retryCount) =>
{
AssertSame(expected, actual, retryCount);
if (validator != null)
{
validator(actual, retryCount);
}
});
}
private static Exception Run(RetryMode retry, Action action, Action validator)
{
Exception exception = null;
for (int i = -1; i < (int)retry; i++)
{
exception = Run(action);
validator(exception, i + 2);
}
return exception;
}
private static Exception Run(Action action)
{
try
{
action();
return null;
}
catch (Exception ex)
{
return ex;
}
}
private static void AssertSerializationMemberName(string memberName, SerializationException actual, int retryCount)
{
// Unfortunately, SerializationException does not provide a way to get our hands on the
// the actual member that was missing from the SerializationInfo, so we need to grok the
// message string.
// Member '[memberName]' was not found.
StringAssert.Contains(actual.Message, "'" + memberName + "'", "Retry Count {0}: Expected SerializationException MemberName to be '{1}'", retryCount, memberName);
}
private static void AssertObjectDisposed(object instance, ObjectDisposedException actual, int retryCount)
{
string objectName = instance.GetType().FullName;
Assert.AreEqual(objectName, actual.ObjectName, "Retry Count {0}: Expected {1}.ObjectName to be '{2}', however, '{3}' is.", retryCount, actual.GetType().Name, objectName, actual.ObjectName);
}
private static void AssertSameParameterName(string parameterName, ArgumentException actual, int retryCount)
{
#if !SILVERLIGHT
Assert.AreEqual(parameterName, actual.ParamName, "Retry Count {0}: Expected {1}.ParamName to be '{2}', however, '{3}' is.", retryCount, actual.GetType().Name, parameterName, actual.ParamName);
#else
// Silverlight doesn't have ArgumentException.ParamName
StringAssert.Contains(actual.Message, parameterName, "Retry Count {0}: Expected {1}.ParamName to be '{2}'", retryCount, actual.GetType().Name, parameterName);
#endif
}
private static void AssertSame(Exception expected, Exception actual, int retryCount)
{
Assert.AreSame(expected, actual, "Retry Count {0}: Expected '{1}' to be thrown, however, '{2}' was thrown.", retryCount, expected, actual);
}
private static void AssertSameInner(Exception innerException, Exception actual, int retryCount)
{
Assert.AreSame(innerException, actual.InnerException, "Retry Count {0}: Expected '{1}' to be the inner exception, however, '{2}' is.", retryCount, innerException, actual.InnerException);
}
private static void AssertIsExactInstanceOf(Type expectedType, Exception actual, int retryCount)
{
if (actual == null)
Assert.Fail("Retry Count {0}: Expected '{1}' to be thrown", retryCount, expectedType);
Type actualType = actual.GetType();
Assert.AreSame(expectedType, actualType, "Retry Count {0}: Expected '{1}' to be thrown, however, '{2}' was thrown.", retryCount, expectedType, actualType);
}
private static void AssertIsExactInstanceOfInner(Type expectedType, Exception actual, int retryCount)
{
if (actual.InnerException == null)
Assert.Fail("Retry Count {0}: Expected '{1}' be the inner exception, however, it is null.", retryCount, expectedType);
Type actualType = actual.InnerException.GetType();
Assert.AreSame(expectedType, actualType, "Retry Count {0}: Expected '{1}' to be the inner exception, however, '{2}' is.", retryCount, expectedType, actualType);
}
}
}