private static bool IsOfExceptionType <T>(Exception thrown, AssertThrowsOptions options) { if ((options & AssertThrowsOptions.AllowDerived) == AssertThrowsOptions.AllowDerived) { return(thrown is T); } return(thrown.GetType() == typeof(T)); }
/// <summary> /// Asserts that the given delegate throws an <see cref="Exception"/> of type <typeparam name="T" />. /// </summary> /// <param name="action"> /// The delagate of type <see cref="Action"/> to execute. /// </param> /// <param name="message"> /// A <see cref="String"/> containing additional information for when the assertion fails. /// </param> /// <param name="options"> /// Specifies whether <see cref="Assert.Throws{T}"/> should require an exact type match when comparing the expected exception type with the thrown exception. The default is <see cref="AssertThrowsOptions.None"/>. /// </param> /// <returns> /// The thrown <see cref="Exception"/>. /// </returns> /// <exception cref="AssertFailedException"> /// <see cref="Exception"/> of type <typeparam name="T"/> was not thrown. /// </exception> public static T Throws <T>(Action action, string message = "", AssertThrowsOptions options = AssertThrowsOptions.None) where T : Exception { Exception exception = RunWithCatch(action); if (exception == null) { Assert.Fail("Expected '{0}' to be thrown. {1}", typeof(T).ToString(), message); } if (!IsOfExceptionType <T>(exception, options)) { Assert.Fail("Expected '{0}' to be thrown, however '{1}' was thrown. {2}", typeof(T), exception.GetType(), message); } return((T)exception); }
/// <summary> /// Asserts that the given async delegate throws an <see cref="Exception"/> of type <typeparam name="T" /> and <see cref="Exception.InnerException"/> /// returns an <see cref="Exception"/> of type <typeparam name="TInner" />. /// </summary> /// <param name="action"> /// The delagate of type <see cref="Action"/> to execute. /// </param> /// <param name="message"> /// A <see cref="String"/> containing additional information for when the assertion fails. /// </param> /// <param name="options"> /// Specifies whether <see cref="Assert.Throws{T}"/> should require an exact type match when comparing the expected exception type with the thrown exception. The default is <see cref="AssertThrowsOptions.None"/>. /// </param> /// <returns> /// The thrown inner <see cref="Exception"/>. /// </returns> /// <exception cref="AssertFailedException"> /// <see cref="Exception"/> of type <typeparam name="T"/> was not thrown. /// <para> /// -or- /// </para> /// <see cref="Exception.InnerException"/> is not of type <typeparam name="TInner"/>. /// </exception> public static TInner Throws <T, TInner>(Action action, string message = "", AssertThrowsOptions options = AssertThrowsOptions.None) where T : Exception where TInner : Exception { T outerException = Throws <T>(action, message, options); if (outerException.InnerException == null) { Assert.Fail("Expected '{0}.InnerException' to be '{1}', however it is null. {2}", typeof(T), typeof(TInner), message); } if (!IsOfExceptionType <TInner>(outerException.InnerException, options)) { Assert.Fail("Expected '{0}.InnerException', to be '{1}', however, '{2}' is. {3}", typeof(T), typeof(TInner), outerException.InnerException.GetType(), message); } return((TInner)outerException.InnerException); }