1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. 2 3 using System; 4 using System.ComponentModel; 5 using System.Globalization; 6 using System.Reflection; 7 using System.Web; 8 9 namespace Microsoft.TestCommon 10 { 11 public partial class AssertEx 12 { 13 /// <summary> 14 /// Determines if your thread's current culture and current UI culture is English. 15 /// </summary> 16 public static bool CurrentCultureIsEnglish 17 { 18 get 19 { 20 return String.Equals(CultureInfo.CurrentCulture.TwoLetterISOLanguageName, "en", StringComparison.OrdinalIgnoreCase) 21 && String.Equals(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName, "en", StringComparison.OrdinalIgnoreCase); 22 } 23 } 24 25 /// <summary> 26 /// Determines whether the specified exception is of the given type (or optionally of a derived type). 27 /// The exception is not allowed to be null; 28 /// </summary> 29 /// <param name="exceptionType">The type of the exception to test for.</param> 30 /// <param name="exception">The exception to be tested.</param> 31 /// <param name="expectedMessage">The expected exception message (only verified on US English OSes).</param> 32 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> IsException(Type exceptionType, Exception exception, string expectedMessage = null, bool allowDerivedExceptions = false)33 public static void IsException(Type exceptionType, Exception exception, string expectedMessage = null, bool allowDerivedExceptions = false) 34 { 35 exception = UnwrapException(exception); 36 NotNull(exception); 37 38 if (allowDerivedExceptions) 39 IsAssignableFrom(exceptionType, exception); 40 else 41 IsType(exceptionType, exception); 42 43 VerifyExceptionMessage(exception, expectedMessage, partialMatch: false); 44 } 45 46 /// <summary> 47 /// Determines whether the specified exception is of the given type (or optionally of a derived type). 48 /// The exception is not allowed to be null; 49 /// </summary> 50 /// <typeparam name="TException">The type of the exception to test for.</typeparam> 51 /// <param name="exception">The exception to be tested.</param> 52 /// <param name="expectedMessage">The expected exception message (only verified on US English OSes).</param> 53 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 54 /// <returns>The exception cast to TException.</returns> 55 public static TException IsException<TException>(Exception exception, string expectedMessage = null, bool allowDerivedExceptions = false) 56 where TException : Exception 57 { 58 TException result; 59 60 exception = UnwrapException(exception); 61 NotNull(exception); 62 63 if (allowDerivedExceptions) 64 result = IsAssignableFrom<TException>(exception); 65 else 66 result = IsType<TException>(exception); 67 68 VerifyExceptionMessage(exception, expectedMessage, partialMatch: false); 69 return result; 70 } 71 72 // We've re-implemented all the xUnit.net Throws code so that we can get this 73 // updated implementation of RecordException which silently unwraps any instances 74 // of AggregateException. This lets our tests better simulate what "await" would do 75 // and thus makes them easier to port to .NET 4.5. RecordException(Action testCode)76 private static Exception RecordException(Action testCode) 77 { 78 try 79 { 80 testCode(); 81 return null; 82 } 83 catch (Exception exception) 84 { 85 return UnwrapException(exception); 86 } 87 } 88 89 /// <summary> 90 /// Verifies that the exact exception is thrown (and not a derived exception type). 91 /// </summary> 92 /// <typeparam name="T">The type of the exception expected to be thrown</typeparam> 93 /// <param name="testCode">A delegate to the code to be tested</param> 94 /// <returns>The exception that was thrown, when successful</returns> 95 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> 96 public static T Throws<T>(Action testCode) 97 where T : Exception 98 { 99 return (T)Throws(typeof(T), testCode); 100 } 101 102 /// <summary> 103 /// Verifies that the exact exception is thrown (and not a derived exception type). 104 /// Generally used to test property accessors. 105 /// </summary> 106 /// <typeparam name="T">The type of the exception expected to be thrown</typeparam> 107 /// <param name="testCode">A delegate to the code to be tested</param> 108 /// <returns>The exception that was thrown, when successful</returns> 109 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> 110 public static T Throws<T>(Func<object> testCode) 111 where T : Exception 112 { 113 return (T)Throws(typeof(T), testCode); 114 } 115 116 /// <summary> 117 /// Verifies that the exact exception is thrown (and not a derived exception type). 118 /// </summary> 119 /// <param name="exceptionType">The type of the exception expected to be thrown</param> 120 /// <param name="testCode">A delegate to the code to be tested</param> 121 /// <returns>The exception that was thrown, when successful</returns> 122 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> Throws(Type exceptionType, Action testCode)123 public static Exception Throws(Type exceptionType, Action testCode) 124 { 125 Exception exception = RecordException(testCode); 126 127 if (exception == null) 128 throw new ThrowsException(exceptionType); 129 130 if (!exceptionType.Equals(exception.GetType())) 131 throw new ThrowsException(exceptionType, exception); 132 133 return exception; 134 } 135 136 /// <summary> 137 /// Verifies that the exact exception is thrown (and not a derived exception type). 138 /// Generally used to test property accessors. 139 /// </summary> 140 /// <param name="exceptionType">The type of the exception expected to be thrown</param> 141 /// <param name="testCode">A delegate to the code to be tested</param> 142 /// <returns>The exception that was thrown, when successful</returns> 143 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> Throws(Type exceptionType, Func<object> testCode)144 public static Exception Throws(Type exceptionType, Func<object> testCode) 145 { 146 return Throws(exceptionType, () => { object unused = testCode(); }); 147 } 148 149 /// <summary> 150 /// Verifies that an exception of the given type (or optionally a derived type) is thrown. 151 /// </summary> 152 /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam> 153 /// <param name="testCode">A delegate to the code to be tested</param> 154 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 155 /// <returns>The exception that was thrown, when successful</returns> 156 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> 157 public static TException Throws<TException>(Action testCode, bool allowDerivedExceptions) 158 where TException : Exception 159 { 160 Type exceptionType = typeof(TException); 161 Exception exception = RecordException(testCode); 162 163 TargetInvocationException tie = exception as TargetInvocationException; 164 if (tie != null) 165 { 166 exception = tie.InnerException; 167 } 168 169 if (exception == null) 170 { 171 throw new ThrowsException(exceptionType); 172 } 173 174 var typedException = exception as TException; 175 if (typedException == null || (!allowDerivedExceptions && typedException.GetType() != typeof(TException))) 176 { 177 throw new ThrowsException(exceptionType, exception); 178 } 179 180 return typedException; 181 } 182 183 /// <summary> 184 /// Verifies that an exception of the given type (or optionally a derived type) is thrown. 185 /// Generally used to test property accessors. 186 /// </summary> 187 /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam> 188 /// <param name="testCode">A delegate to the code to be tested</param> 189 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 190 /// <returns>The exception that was thrown, when successful</returns> 191 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> 192 public static TException Throws<TException>(Func<object> testCode, bool allowDerivedExceptions) 193 where TException : Exception 194 { 195 return Throws<TException>(() => { testCode(); }, allowDerivedExceptions); 196 } 197 198 /// <summary> 199 /// Verifies that an exception of the given type (or optionally a derived type) is thrown. 200 /// Also verified that the exception message matches if the current thread locale is English. 201 /// </summary> 202 /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam> 203 /// <param name="testCode">A delegate to the code to be tested</param> 204 /// <param name="exceptionMessage">The exception message to verify</param> 205 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 206 /// <returns>The exception that was thrown, when successful</returns> 207 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> 208 public static TException Throws<TException>(Action testCode, string exceptionMessage, bool allowDerivedExceptions = false) 209 where TException : Exception 210 { 211 var ex = Throws<TException>(testCode, allowDerivedExceptions); 212 VerifyExceptionMessage(ex, exceptionMessage); 213 return ex; 214 } 215 216 /// <summary> 217 /// Verifies that an exception of the given type (or optionally a derived type) is thrown. 218 /// Also verified that the exception message matches if the current thread locale is English. 219 /// </summary> 220 /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam> 221 /// <param name="testCode">A delegate to the code to be tested</param> 222 /// <param name="exceptionMessage">The exception message to verify</param> 223 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 224 /// <returns>The exception that was thrown, when successful</returns> 225 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> 226 public static TException Throws<TException>(Func<object> testCode, string exceptionMessage, bool allowDerivedExceptions = false) 227 where TException : Exception 228 { 229 return Throws<TException>(() => { testCode(); }, exceptionMessage, allowDerivedExceptions); 230 } 231 232 /// <summary> 233 /// Verifies that the code throws an <see cref="ArgumentException"/> (or optionally any exception which derives from it). 234 /// </summary> 235 /// <param name="testCode">A delegate to the code to be tested</param> 236 /// <param name="paramName">The name of the parameter that should throw the exception</param> 237 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 238 /// <returns>The exception that was thrown, when successful</returns> 239 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgument(Action testCode, string paramName, bool allowDerivedExceptions = false)240 public static ArgumentException ThrowsArgument(Action testCode, string paramName, bool allowDerivedExceptions = false) 241 { 242 var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions); 243 244 if (paramName != null) 245 { 246 Equal(paramName, ex.ParamName); 247 } 248 249 return ex; 250 } 251 252 /// <summary> 253 /// Verifies that the code throws an <see cref="ArgumentException"/> (or optionally any exception which derives from it). 254 /// </summary> 255 /// <param name="testCode">A delegate to the code to be tested</param> 256 /// <param name="paramName">The name of the parameter that should throw the exception</param> 257 /// <param name="exceptionMessage">The exception message to verify</param> 258 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 259 /// <returns>The exception that was thrown, when successful</returns> 260 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgument(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false)261 public static ArgumentException ThrowsArgument(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false) 262 { 263 var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions); 264 265 if (paramName != null) 266 { 267 Equal(paramName, ex.ParamName); 268 } 269 270 VerifyExceptionMessage(ex, exceptionMessage, partialMatch: true); 271 272 return ex; 273 } 274 275 /// <summary> 276 /// Verifies that the code throws an ArgumentException (or optionally any exception which derives from it). 277 /// </summary> 278 /// <param name="testCode">A delegate to the code to be tested</param> 279 /// <param name="paramName">The name of the parameter that should throw the exception</param> 280 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 281 /// <returns>The exception that was thrown, when successful</returns> 282 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgument(Func<object> testCode, string paramName, bool allowDerivedExceptions = false)283 public static ArgumentException ThrowsArgument(Func<object> testCode, string paramName, bool allowDerivedExceptions = false) 284 { 285 var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions); 286 287 if (paramName != null) 288 { 289 Equal(paramName, ex.ParamName); 290 } 291 292 return ex; 293 } 294 295 /// <summary> 296 /// Verifies that the code throws an ArgumentNullException (or optionally any exception which derives from it). 297 /// </summary> 298 /// <param name="testCode">A delegate to the code to be tested</param> 299 /// <param name="paramName">The name of the parameter that should throw the exception</param> 300 /// <returns>The exception that was thrown, when successful</returns> 301 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentNull(Action testCode, string paramName)302 public static ArgumentNullException ThrowsArgumentNull(Action testCode, string paramName) 303 { 304 var ex = Throws<ArgumentNullException>(testCode, allowDerivedExceptions: false); 305 306 if (paramName != null) 307 { 308 Equal(paramName, ex.ParamName); 309 } 310 311 return ex; 312 } 313 314 /// <summary> 315 /// Verifies that the code throws an ArgumentNullException with the expected message that indicates that the value cannot 316 /// be null or empty. 317 /// </summary> 318 /// <param name="testCode">A delegate to the code to be tested</param> 319 /// <param name="paramName">The name of the parameter that should throw the exception</param> 320 /// <returns>The exception that was thrown, when successful</returns> 321 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentNullOrEmpty(Action testCode, string paramName)322 public static ArgumentException ThrowsArgumentNullOrEmpty(Action testCode, string paramName) 323 { 324 return Throws<ArgumentException>(testCode, "Value cannot be null or empty.\r\nParameter name: " + paramName, allowDerivedExceptions: false); 325 } 326 327 /// <summary> 328 /// Verifies that the code throws an ArgumentNullException with the expected message that indicates that the value cannot 329 /// be null or empty string. 330 /// </summary> 331 /// <param name="testCode">A delegate to the code to be tested</param> 332 /// <param name="paramName">The name of the parameter that should throw the exception</param> 333 /// <returns>The exception that was thrown, when successful</returns> 334 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentNullOrEmptyString(Action testCode, string paramName)335 public static ArgumentException ThrowsArgumentNullOrEmptyString(Action testCode, string paramName) 336 { 337 return ThrowsArgument(testCode, paramName, "Value cannot be null or an empty string.", allowDerivedExceptions: true); 338 } 339 340 /// <summary> 341 /// Verifies that the code throws an ArgumentOutOfRangeException (or optionally any exception which derives from it). 342 /// </summary> 343 /// <param name="testCode">A delegate to the code to be tested</param> 344 /// <param name="paramName">The name of the parameter that should throw the exception</param> 345 /// <param name="exceptionMessage">The exception message to verify</param> 346 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 347 /// <param name="actualValue">The actual value provided</param> 348 /// <returns>The exception that was thrown, when successful</returns> 349 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentOutOfRange(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false, object actualValue = null)350 public static ArgumentOutOfRangeException ThrowsArgumentOutOfRange(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false, object actualValue = null) 351 { 352 exceptionMessage = exceptionMessage != null 353 ? exceptionMessage + "\r\nParameter name: " + paramName + 354 (actualValue != null ? "\r\nActual value was " + actualValue.ToString() + "." : "") 355 : exceptionMessage; 356 var ex = Throws<ArgumentOutOfRangeException>(testCode, exceptionMessage, allowDerivedExceptions); 357 358 if (paramName != null) 359 { 360 Equal(paramName, ex.ParamName); 361 } 362 363 return ex; 364 } 365 366 /// <summary> 367 /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that 368 /// the value must be greater than the given <paramref name="value"/>. 369 /// </summary> 370 /// <param name="testCode">A delegate to the code to be tested</param> 371 /// <param name="paramName">The name of the parameter that should throw the exception</param> 372 /// <param name="actualValue">The actual value provided.</param> 373 /// <param name="value">The expected limit value.</param> 374 /// <returns>The exception that was thrown, when successful</returns> 375 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentGreaterThan(Action testCode, string paramName, string value, object actualValue = null)376 public static ArgumentOutOfRangeException ThrowsArgumentGreaterThan(Action testCode, string paramName, string value, object actualValue = null) 377 { 378 return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be greater than {0}.", value), false, actualValue); 379 } 380 381 /// <summary> 382 /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that 383 /// the value must be greater than or equal to the given value. 384 /// </summary> 385 /// <param name="testCode">A delegate to the code to be tested</param> 386 /// <param name="paramName">The name of the parameter that should throw the exception</param> 387 /// <param name="value">The expected limit value.</param> 388 /// <returns>The exception that was thrown, when successful</returns> 389 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentGreaterThanOrEqualTo(Action testCode, string paramName, string value, object actualValue = null)390 public static ArgumentOutOfRangeException ThrowsArgumentGreaterThanOrEqualTo(Action testCode, string paramName, string value, object actualValue = null) 391 { 392 return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be greater than or equal to {0}.", value), false, actualValue); 393 } 394 395 /// <summary> 396 /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that 397 /// the value must be less than the given <paramref name="maxValue"/>. 398 /// </summary> 399 /// <param name="testCode">A delegate to the code to be tested</param> 400 /// <param name="paramName">The name of the parameter that should throw the exception</param> 401 /// <param name="actualValue">The actual value provided.</param> 402 /// <param name="maxValue">The expected limit value.</param> 403 /// <returns>The exception that was thrown, when successful</returns> 404 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentLessThan(Action testCode, string paramName, string maxValue, object actualValue = null)405 public static ArgumentOutOfRangeException ThrowsArgumentLessThan(Action testCode, string paramName, string maxValue, object actualValue = null) 406 { 407 return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be less than {0}.", maxValue), false, actualValue); 408 } 409 410 /// <summary> 411 /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that 412 /// the value must be less than or equal to the given <paramref name="maxValue"/>. 413 /// </summary> 414 /// <param name="testCode">A delegate to the code to be tested</param> 415 /// <param name="paramName">The name of the parameter that should throw the exception</param> 416 /// <param name="actualValue">The actual value provided.</param> 417 /// <param name="maxValue">The expected limit value.</param> 418 /// <returns>The exception that was thrown, when successful</returns> 419 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsArgumentLessThanOrEqualTo(Action testCode, string paramName, string maxValue, object actualValue = null)420 public static ArgumentOutOfRangeException ThrowsArgumentLessThanOrEqualTo(Action testCode, string paramName, string maxValue, object actualValue = null) 421 { 422 return ThrowsArgumentOutOfRange(testCode, paramName, String.Format("Value must be less than or equal to {0}.", maxValue), false, actualValue); 423 } 424 425 /// <summary> 426 /// Verifies that the code throws an HttpException (or optionally any exception which derives from it). 427 /// </summary> 428 /// <param name="testCode">A delegate to the code to be tested</param> 429 /// <param name="exceptionMessage">The exception message to verify</param> 430 /// <param name="httpCode">The expected HTTP status code of the exception</param> 431 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 432 /// <returns>The exception that was thrown, when successful</returns> 433 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsHttpException(Action testCode, string exceptionMessage, int httpCode, bool allowDerivedExceptions = false)434 public static HttpException ThrowsHttpException(Action testCode, string exceptionMessage, int httpCode, bool allowDerivedExceptions = false) 435 { 436 var ex = Throws<HttpException>(testCode, exceptionMessage, allowDerivedExceptions); 437 Equal(httpCode, ex.GetHttpCode()); 438 return ex; 439 } 440 441 /// <summary> 442 /// Verifies that the code throws an InvalidEnumArgumentException (or optionally any exception which derives from it). 443 /// </summary> 444 /// <param name="testCode">A delegate to the code to be tested</param> 445 /// <param name="paramName">The name of the parameter that should throw the exception</param> 446 /// <param name="invalidValue">The expected invalid value that should appear in the message</param> 447 /// <param name="enumType">The type of the enumeration</param> 448 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 449 /// <returns>The exception that was thrown, when successful</returns> 450 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false)451 public static InvalidEnumArgumentException ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false) 452 { 453 return Throws<InvalidEnumArgumentException>( 454 testCode, 455 String.Format("The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}Parameter name: {0}", paramName, invalidValue, enumType.Name, Environment.NewLine), 456 allowDerivedExceptions 457 ); 458 } 459 460 /// <summary> 461 /// Verifies that the code throws an HttpException (or optionally any exception which derives from it). 462 /// </summary> 463 /// <param name="testCode">A delegate to the code to be tested</param> 464 /// <param name="objectName">The name of the object that was dispose</param> 465 /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param> 466 /// <returns>The exception that was thrown, when successful</returns> 467 /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception> ThrowsObjectDisposed(Action testCode, string objectName, bool allowDerivedExceptions = false)468 public static ObjectDisposedException ThrowsObjectDisposed(Action testCode, string objectName, bool allowDerivedExceptions = false) 469 { 470 var ex = Throws<ObjectDisposedException>(testCode, allowDerivedExceptions); 471 472 if (objectName != null) 473 { 474 Equal(objectName, ex.ObjectName); 475 } 476 477 return ex; 478 } 479 UnwrapException(Exception exception)480 private static Exception UnwrapException(Exception exception) 481 { 482 AggregateException aggEx; 483 while ((aggEx = exception as AggregateException) != null) 484 exception = aggEx.GetBaseException(); 485 486 return exception; 487 } 488 VerifyExceptionMessage(Exception exception, string expectedMessage, bool partialMatch = false)489 private static void VerifyExceptionMessage(Exception exception, string expectedMessage, bool partialMatch = false) 490 { 491 if (expectedMessage != null && CurrentCultureIsEnglish) 492 { 493 if (!partialMatch) 494 { 495 Equal(expectedMessage, exception.Message); 496 } 497 else 498 { 499 Contains(expectedMessage, exception.Message); 500 } 501 } 502 } 503 504 // Custom ThrowsException so we can filter the stack trace. 505 private class ThrowsException : Xunit.Sdk.ThrowsException 506 { ThrowsException(Type type)507 public ThrowsException(Type type) : base(type) { } 508 ThrowsException(Type type, Exception ex)509 public ThrowsException(Type type, Exception ex) : base(type, ex) { } 510 ExcludeStackFrame(string stackFrame)511 protected override bool ExcludeStackFrame(string stackFrame) 512 { 513 if (stackFrame.StartsWith("at Microsoft.TestCommon.AssertEx.", StringComparison.OrdinalIgnoreCase)) 514 { 515 return true; 516 } 517 518 return base.ExcludeStackFrame(stackFrame); 519 } 520 } 521 } 522 } 523