/// <summary> /// Tests if the cookie has the Domain flag /// </summary> /// <param name="more"></param> /// <param name="expectedDomain"></param> /// <returns></returns> public static IMore <Cookie> Domain( this ICanAddMatcher <Cookie> more, string expectedDomain ) { return(more.Domain(expectedDomain, NULL_STRING)); }
/// <summary> /// Tests if the cookie has the HttpOnly flag /// </summary> /// <param name="more"></param> /// <param name="customMessage"></param> /// <returns></returns> public static IMore <Cookie> HttpOnly( this ICanAddMatcher <Cookie> more, string customMessage ) { return(more.HttpOnly(() => customMessage)); }
/// <summary> /// Tests for any parameter on a .Method continuation /// </summary> /// <param name="continuation"></param> /// <param name="parameterName"></param> /// <returns></returns> public static IMore <MethodInfo> Parameter( this ICanAddMatcher <MethodInfo> continuation, string parameterName ) { return(continuation.Parameter(parameterName, NULL_STRING)); }
/// <summary> /// Use to compose expectations into one matcher /// </summary> /// <param name="continuation">Continuation to operate on</param> /// <param name="expectationsRunner">Runs your composed expectations</param> /// <param name="messageGenerator">Generates the final message, passing in the actual instance being tested as well as a boolean for passed/failed</param> /// <typeparam name="T"></typeparam> public static IMore <T> Compose <T>( this ICanAddMatcher <T> continuation, Action <T> expectationsRunner, Func <T, bool, string> messageGenerator ) { continuation.AddMatcher(actual => { try { expectationsRunner(actual); return(new MatcherResult(true, () => messageGenerator(actual, true))); } catch (UnmetExpectationException e) { return(new MatcherResult(false, () => FinalMessageFor( new[] { "Specifically:", e.Message }, messageGenerator?.Invoke(actual, false) ) )); } }); return(continuation.More()); }
/// <summary> /// Expects the Action to throw any kind of exception /// </summary> /// <param name="src">Action to run</param> /// <param name="customMessage">Custom message to add to failure messages</param> /// <returns>Continuation which can be used to test exception messages</returns> public static IThrowContinuation <Exception> Throw( this ICanAddMatcher <Action> src, string customMessage ) { return(src.Throw(() => customMessage)); }
private static T TryGetActual <T>(ICanAddMatcher <T> matcher) { if (matcher == null) { throw new InvalidOperationException( $"Can't get an Actual value from a NULL matcher" ); } var prop = matcher?.GetType() .GetProperties() .FirstOrDefault(pi => pi.Name.ToLower() == "actual"); if (prop == null) { throw new InvalidOperationException( $"Failed to GetActual on type {typeof(T)}. GetActual only works on IHasActual<T> or objects with an 'Actual' property"); } try { return((T)prop.GetValue(matcher)); } catch { throw new InvalidOperationException( @$ "Unable to get Actual value matching type { typeof(T) } from { matcher.Stringify() }"
/// <summary> /// Expects the action to throw an exception of type T /// </summary> /// <param name="src">Action to test</param> /// <param name="customMessage">Custom message to add to failure messages</param> /// <typeparam name="T">Type of exception which is expected</typeparam> /// <returns>Continuation which can be used to test exception messages</returns> public static IThrowContinuation <T> Throw <T>( this ICanAddMatcher <Action> src, string customMessage ) where T : Exception { return(src.Throw <T>(() => customMessage)); }
/// <summary> /// Tests if the cookie has the Secure flag /// </summary> /// <param name="more"></param> /// <param name="customMessage"></param> /// <returns></returns> public static IMore <Cookie> Secure( this ICanAddMatcher <Cookie> more, string customMessage ) { return(more.Secure(() => customMessage)); }
private static void AddRegexMatcher( ICanAddMatcher <string> matcher, Regex regex, Func <string> customMessageGenerator ) { matcher.AddMatcher( actual => { var passed = regex.IsMatch(actual); return(new MatcherResult( passed, FinalMessageFor( () => new[] { "Expected", actual.Stringify(), $"{passed.AsNot()}to match regex", $"\"{regex}\"" }, customMessageGenerator ) )); }); }
private static void RunIntersectioEqualityTest <T>( ICanAddMatcher <T> continuation, object expected, Func <string> customMessageGenerator, params object[] customEqualityComparers ) { continuation.AddMatcher( actual => { var result = DeepTestHelpers.AreIntersectionEqual( actual, expected, customEqualityComparers); return(new MatcherResult( result.AreEqual, FinalMessageFor( () => new[] { "Expected", actual.Stringify(), $"{result.AreEqual.AsNot()}to intersection equal", expected.Stringify() }.Concat(result.Errors).ToArray(), customMessageGenerator ) )); } ); }
/// <summary> /// Tests that the provided method info returns the expected type /// </summary> /// <param name="continuation"></param> /// <param name="expected"></param> /// <param name="customMessageGenerator"></param> /// <returns></returns> /// <exception cref="NotImplementedException"></exception> public static IMore <MethodInfo> Returns( this ICanAddMatcher <MethodInfo> continuation, Type expected, Func <string> customMessageGenerator ) { return(continuation.AddMatcher(actual => { if (actual is null) { throw new InvalidOperationException( $"Cannot test return type on null MethodInfo" ); } var passed = actual.ReturnType == expected; return new MatcherResult( passed, FinalMessageFor( () => $@"Expected '{ actual.Name }' { passed.AsNot() } to have return value of type {expected} (found: {actual.ReturnType})", customMessageGenerator ) ); })); }
/// <summary> /// Add a matcher onto a Collection continuation /// </summary> /// <param name="continuation">Continuation to add matcher to</param> /// <param name="matcher">Matcher to run</param> /// <typeparam name="T">Type of the object under test</typeparam> public static void AddMatcher <T>( this ICanAddMatcher <IEnumerable <T> > continuation, Func <IEnumerable <T>, IMatcherResult> matcher ) { AddMatcherPrivate(continuation, matcher); }
/// <summary> /// Tests the return value on a .Method continuation /// </summary> /// <param name="continuation"></param> /// <param name="expected"></param> /// <returns></returns> public static IMore <MethodInfo> Returns( this ICanAddMatcher <MethodInfo> continuation, Type expected ) { return(continuation.Returns(expected, NULL_STRING)); }
/// <summary> /// Expects the action to throw an exception of type T /// </summary> /// <param name="src">Action to test</param> /// <typeparam name="T">Type of exception which is expected</typeparam> /// <returns>Continuaiotn which can be used to test exception messages</returns> public static IThrowContinuation Throw <T>( this ICanAddMatcher <Action> src ) where T : Exception { var continuation = new ThrowContinuation(); var expectedType = typeof(T); src.AddMatcher(fn => { MatcherResult result; try { fn(); result = new MatcherResult(false, $"Expected to throw an exception of type {expectedType.Name} but none was thrown"); } catch (Exception ex) { var passed = ex is T; var message = passed ? $"Expected not to throw an exception of type {expectedType.Name}" : $"Expected to throw an exception of type {expectedType.Name} but {ex.GetType().Name} was thrown instead ({ex.Message})"; result = new MatcherResult(passed, message); continuation.Exception = ex; } return(result); }); return(continuation); }
/// <summary> /// Most general matcher add - onto ICanAddMatcher<T> /// </summary> /// <param name="continuation">Continuation to add matcher to</param> /// <param name="matcher">Matcher to run</param> /// <typeparam name="T">Type of the object under test</typeparam> public static IMore <T> AddMatcher <T>( this ICanAddMatcher <T> continuation, Func <T, IMatcherResult> matcher) { AddMatcherPrivate(continuation, matcher); return(continuation.More()); }
/// <summary> /// Use to compose expectations into one matcher /// </summary> /// <param name="continuation">Continuation to operate on</param> /// <param name="expectationsRunner">Runs your composed expectations</param> /// <param name="messageGenerator">Generates the final message, passing in the actual instance being tested as well as a boolean for passed/failed</param> /// <typeparam name="T"></typeparam> public static IMore <T> Compose <T>( this ICanAddMatcher <T> continuation, Action <T> expectationsRunner, Func <T, bool, string> messageGenerator ) { continuation.AddMatcher(actual => { try { // if we're using custom assertions, we won't get an UnmetExpectationException // on a failure // worse, if those custom assertions are from NUnit, we can't stop the failure // -> it's part of the design of NUnit using var _ = Assertions.TemporarilyUseDefaultAssertionsFactoryForThisThread(); expectationsRunner(actual); return(new MatcherResult(true, () => messageGenerator(actual, true))); } catch (UnmetExpectationException e) { return(new MatcherResult(false, () => FinalMessageFor( new[] { "Specifically:", e.Message }, messageGenerator?.Invoke(actual, false) ) )); } }); return(continuation.More()); }
/// <summary> /// Tests if the value under test contains a given string. May be continued /// with ".And" /// </summary> /// <param name="continuation">Continuation to act on</param> /// <param name="search">String value to search for</param> /// <returns>IStringContainContinuation onto which you can chain .And</returns> public static IStringMore Contain( this ICanAddMatcher <string> continuation, string search ) { return(continuation.Contain(search, NULL_STRING)); }
private static void AddRegexMatcher( ICanAddMatcher <string> matcher, string regex, Func <string> customMessage ) { AddRegexMatcher(matcher, CompileRegexFor(regex), customMessage); }
private static void CheckContain <T>(ICanAddMatcher <IEnumerable <T> > contain) { if (contain == null) { throw new ArgumentNullException(nameof(contain), $"Exactly<T>() cannot extend null IContain<IEnumerable<{typeof(T).Name}>>"); } }
/// <summary> /// Tests the return value on a .Method continuation /// </summary> /// <param name="continuation"></param> /// <param name="expected"></param> /// <param name="customMessage"></param> /// <returns></returns> public static IMore <MethodInfo> Returns( this ICanAddMatcher <MethodInfo> continuation, Type expected, string customMessage ) { return(continuation.Returns(expected, () => customMessage)); }
/// <summary> /// Tests if the value under test contains a given string. May be continued /// with ".And" /// </summary> /// <param name="continuation">Continuation to act on</param> /// <param name="search">String value to search for</param> /// <param name="customMessage">Custom message to include in failure messages</param> /// <returns>IStringContainContinuation onto which you can chain .And</returns> public static IStringMore Contain( this ICanAddMatcher <string> continuation, string search, string customMessage ) { return(continuation.Contain(search, () => customMessage)); }
/// <summary> /// Tests if the cookie has the Domain flag /// </summary> /// <param name="more"></param> /// <param name="expectedDomain"></param> /// <param name="customMessage"></param> /// <returns></returns> public static IMore <Cookie> Domain( this ICanAddMatcher <Cookie> more, string expectedDomain, string customMessage ) { return(more.Domain(expectedDomain, () => customMessage)); }
public static IStringContainContinuation Contain( this ICanAddMatcher <string> continuation, string search ) { AddContainsMatcherTo(continuation, search); return(new StringContainContinuation(continuation)); }
/// <summary> /// Use to compose expectations into one matcher /// </summary> /// <param name="continuation">Continuation to operate on</param> /// <param name="expectationsRunner">Runs your composed expectations</param> /// <param name="callingMethod"></param> /// <typeparam name="T"></typeparam> public static IMore <T> Compose <T>( this ICanAddMatcher <T> continuation, Action <T> expectationsRunner, [CallerMemberName] string callingMethod = null ) { return(continuation.Compose(expectationsRunner, (a, b) => $"Expectation \"{callingMethod}\" should {(!b).AsNot()}have failed.")); }
private static IMore <T> Property <T>( this ICanAddMatcher <T> canAddMatcher, string property, Func <string> customMessageGenerator ) { return(canAddMatcher.AddMatcher(actual => { if (string.IsNullOrWhiteSpace(property)) { return Fail(() => "Provided property name is null or whitespace"); } if (actual is null) { return Fail(() => "Actual value is null"); } actual.SetMetadata(METADATA_KEY_PROPERTY_NAME, property); var actualType = actual.ResolveToType(); var propInfo = actualType.GetProperty(property, PUBLIC_INSTANCE); if (propInfo is null) { return new MatcherResult( false, () => $@"Expected { actualType.PrettyName() } { false.AsNot() }to have a public property named '{property}'" ); } actual.SetMetadata(METADATA_KEY_PROPERTY_INFO, propInfo); return new MatcherResult( true, FinalMessageFor( () => $"Expected {actual.Stringify()} {true.AsNot()}to have property '{property}'", customMessageGenerator ) ); })); MatcherResult Fail(Func <string> defaultGenerator) { return(new MatcherResult( false, () => FinalMessageFor( defaultGenerator, customMessageGenerator ) )); } }
/// <summary> /// Creates an object with .And on it which you can use to chain on more /// expectations, eg Expect(1).To.Be.SomeCustomMatcher().And.SomeOtherMatcher() /// </summary> /// <param name="continuation"></param> /// <returns></returns> public static IStringMore More( this ICanAddMatcher <string> continuation ) { return(ContinuationFactory.Create <string, StringMore>( continuation.GetActual(), continuation as IExpectationContext <string> )); }
/// <summary> /// Use to compose expectations into one matcher /// </summary> /// <param name="continuation">Continuation to operate on</param> /// <param name="expectationsRunner">Runs your composed expectations</param> /// <param name="callingMethod"></param> /// <typeparam name="T"></typeparam> public static IMore <IEnumerable <T> > Compose <T>( this ICanAddMatcher <IEnumerable <T> > continuation, Action <IEnumerable <T> > expectationsRunner, [CallerMemberName] string callingMethod = null ) { return(continuation.Compose(expectationsRunner, (a, b) => $"{callingMethod} should {b.AsNot()}have passed.")); }
public CountMatchDeepEqual( ICanAddMatcher <T> continuation, CountMatchMethods method, int compare) { Continuation = continuation; Method = method; ExpectedCount = compare; }
public CountMatchMatched( ICanAddMatcher <T> continuation, CountMatchMethods method, int compare) { Continuation = continuation; Method = method; Compare = compare; }
/// <summary> /// Attempts to sniff the actual value off of a continuation /// </summary> /// <param name="matcher">Continuation to operate on</param> /// <typeparam name="T">Expected type of the Actual value</typeparam> /// <returns>Actual value, if available</returns> public static T GetActual <T>(this ICanAddMatcher <T> matcher) { // ReSharper disable once UsePatternMatching var explicitImpl = matcher as IHasActual <T>; return(explicitImpl == null ? TryGetActual(matcher) : explicitImpl.Actual); }