/// <summary> /// Checks that the actual <see cref="IDictionary"/> contains the expected value. /// </summary> /// <typeparam name="K"> /// The type of the key element. /// </typeparam> /// <param name="check"> /// The fluent check to be extended. /// </param> /// <param name="expectedValue"> /// The expected value. /// </param> /// <returns> /// A check link. /// </returns> public static ICheckLink <ICheck <IDictionary> > ContainsValue <K>(this ICheck <IDictionary> check, K expectedValue) { var checker = ExtensibilityHelper.ExtractChecker(check); return(checker.ExecuteCheck( () => { var found = false; foreach (var item in checker.Value.Values) { if (item.Equals(expectedValue)) { found = true; break; } } if (!found) { var message = FluentMessage.BuildMessage("The {0} does not contain the expected value.").For("dictionary").On(checker.Value).And.Expected(expectedValue).Label("given value:").ToString(); throw new FluentCheckException(message); } }, FluentMessage.BuildMessage("The {0} does contain the given value, whereas it must not.").For("dictionary").On(checker.Value).And.Expected(expectedValue).Label("Expected value:").ToString())); }
/// <summary> /// Checks that the enumerable contains only the values present in another enumerable, and nothing else, in any order. /// Note: this check succeeded with empty value. /// </summary> /// <param name="check">The fluent check to be extended.</param> /// <param name="expectedValues">The expected values to be found.</param> /// <returns> /// A check link. /// </returns> /// <exception cref="FluentCheckException">The enumerable does not contain only the expected values present in the other enumerable.</exception> public static ICheckLink <ICheck <IEnumerable> > IsOnlyMadeOf(this ICheck <IEnumerable> check, IEnumerable expectedValues) { var checker = ExtensibilityHelper.ExtractChecker(check); return(checker.ExecuteCheck( () => { // TODO: refactor this implementation? if (checker.Value == null && expectedValues == null) { return; } if (checker.Value == null && expectedValues != null) { var message = FluentMessage.BuildMessage("The {0} is null and thus, does not contain exactly the given value(s).").For("enumerable").On(checker.Value).And.ExpectedValues(expectedValues).ToString(); throw new FluentCheckException(message); } var unexpectedValuesFound = ExtractUnexpectedValues(checker.Value, expectedValues); if (unexpectedValuesFound.Count > 0) { var message = FluentMessage.BuildMessage(string.Format("The {{0}} does not contain only the given value(s).\nIt contains also other values:\n\t[{0}]", unexpectedValuesFound.ToEnumeratedString().DoubleCurlyBraces())).For("enumerable").On(checker.Value).And.ExpectedValues(expectedValues).ToString(); throw new FluentCheckException(message); } }, FluentMessage.BuildMessage("The {0} contains only the given values whereas it must not.").For("enumerable").On(checker.Value).And.ExpectedValues(expectedValues).ToString())); }
/// <summary> /// Checks if the given dynamic has the expected reference. /// </summary> /// <param name="expected">Expected reference.</param> public DynamicCheckLink IsSameReferenceAs(dynamic expected) { if (this.negated != (object.ReferenceEquals(this.value, expected))) { return(new DynamicCheckLink(this)); } string message; if (this.negated) { message = FluentMessage .BuildMessage("The {0} is the expected reference whereas it must not.") .For("dynamic") .AddCustomMessage(this.CustomMessage) .Expected(expected) .Comparison("different from") .And .On <object>(this.value).ToString(); } else { message = FluentMessage .BuildMessage("The {0} is not the expected reference.") .For("dynamic") .AddCustomMessage(this.CustomMessage) .Expected(expected) .And .On <object>(this.value).ToString(); } throw new FluentCheckException(message); }
/// <summary> /// Builds the error message related to the type comparison. This should be called only if the test failed (no matter it is negated or not). /// Warning: Should not call this method with nullable types. Indeed, the Nullable types are treated specially by CLR and it is impossible to have a boxed instance of a nullable type. /// Instead, boxing a nullable type will result in a null reference (if HasValue is false), or the boxed value (if there is a value). /// </summary> /// <param name="value">The checked value.</param> /// <param name="typeOperand">The other type operand.</param> /// <param name="isSameType">A value indicating whether the two types are identical or not. <c>true</c> if they are equal; <c>false</c> otherwise.</param> /// <returns> /// The error message related to the type comparison. /// </returns> public static string BuildErrorMessage(object value, Type typeOperand, bool isSameType) { MessageBlock message; if (isSameType) { message = FluentMessage.BuildMessage(string.Format("The {{0}} is an instance of [{0}] whereas it must not.", typeOperand.ToStringProperlyFormated())) .For("value") .On(value) .WithType() .And.ExpectedType(typeOperand) .WithType() .Comparison("different from"); } else if (value != null && value.GetType().FullName == typeOperand.FullName) { // cannot discriminate from type name message = FluentMessage.BuildMessage("The {0} .") .On(value) .WithType(true, true) .And.ExpectedType(typeOperand) .WithType(true, true); } else { message = FluentMessage.BuildMessage("The {0} is not an instance of the expected type.") .On(value) .WithType() .And.ExpectedType(typeOperand) .WithType(); } return(message.ToString()); }
/// <summary> /// Builds the error message related to the Equality verification. This should be called only if the test failed (no matter it is negated or not). /// </summary> /// <param name="instance">The checked instance.</param> /// <param name="expected">The other operand.</param> /// <param name="isEqual">A value indicating whether the two values are equal or not. <c>true</c> if they are equal; <c>false</c> otherwise.</param> /// <returns>The error message related to the Equality verification.</returns> public static string BuildErrorMessage(object instance, object expected, bool isEqual) { string message; if (isEqual) { message = FluentMessage.BuildMessage("The {0} is equal to the {1} whereas it must not.") .Expected(expected) .Comparison("different from") .WithType() .ToString(); } else { // shall we display the type as well? var withType = (instance != null && expected != null && instance.GetType() != expected.GetType()) || (instance == null) || (expected == null); // shall we display the hash too var withHash = instance != null && expected != null && instance.GetType() == expected.GetType() && instance.ToString() == expected.ToString(); message = FluentMessage.BuildMessage("The {0} is different from the {1}.") .On(instance) .WithType(withType) .WithHashCode(withHash) .And.Expected(expected) .WithType(withType) .WithHashCode(withHash).ToString(); } return(message); }
/// <summary> /// Checks if the given dynamic is null. /// </summary> public DynamicCheckLink IsNotNull() { if (this.negated != (this.value != null)) { return(new DynamicCheckLink(this)); } string message; if (this.negated) { message = FluentMessage.BuildMessage("The {0} is not null whereas it must.") .AddCustomMessage(this.CustomMessage) .For("dynamic") .On <object>(this.value).ToString(); } else { message = FluentMessage.BuildMessage("The {0} is null whereas it must not.") .AddCustomMessage(this.CustomMessage) .For("dynamic") .On <object>(this.value).ToString(); } throw new FluentCheckException(message); }
/// <summary> /// Checks that the checked <see cref="string"/> contains the expected list of strings only once. /// </summary> /// <param name="chainedCheckLink"> /// The chained fluent check. /// </param> /// <returns> /// A check link. /// </returns> public static IExtendableCheckLink <string, string[]> Once(this IExtendableCheckLink <string, string[]> chainedCheckLink) { var checker = chainedCheckLink.And as ICheckForExtensibility <string, ICheck <string> >; var value = checker.Value; var comparand = chainedCheckLink.OriginalComparand; foreach (var text in comparand) { var firstIndex = value.IndexOf(text); var lastIndexOf = value.LastIndexOf(text); if (firstIndex != lastIndexOf) { // failed var message = FluentMessage.BuildMessage(string.Format("The {{0}} contains {0} at {1} and {2}, where as it must contains it once.", text.ToStringProperlyFormated().DoubleCurlyBraces(), firstIndex, lastIndexOf)) .For("string") .On(value) .And.Expected(comparand) .Label("Expected content once"); throw new FluentCheckException(message.ToString()); } } return(chainedCheckLink); }
/// <summary> /// Checks that the checked <see cref="string"/> contains the expected list of strings in the correct order. /// </summary> /// <param name="chainedCheckLink"> /// The chained fluent check. /// </param> /// <returns> /// A check link. /// </returns> public static IExtendableCheckLink <string, string[]> InThatOrder(this IExtendableCheckLink <string, string[]> chainedCheckLink) { var checker = chainedCheckLink.And as ICheckForExtensibility <string, ICheck <string> >; var value = checker.Value; var comparand = chainedCheckLink.OriginalComparand; var lastIndex = 0; foreach (var text in comparand) { lastIndex = value.IndexOf(text, lastIndex); if (lastIndex < 0) { // failed var message = FluentMessage.BuildMessage( "The {0} does not contain the expected strings in the correct order.") .For("string") .On(value) .And.Expected(comparand) .Label("Expected content: "); throw new FluentCheckException(message.ToString()); } } return(chainedCheckLink); }
/// <summary> /// Checks that the CPU time is below a specified threshold. /// </summary> /// <typeparam name="T">Type of the checked type.</typeparam> /// <param name="check">The fluent check to be extended. /// </param> /// <param name="threshold"> /// The threshold. /// </param> /// <param name="timeUnit"> /// The time unit of the given threshold. /// </param> /// <returns> /// A check link. /// </returns> /// <exception cref="FluentCheckException"> /// Execution was strictly above limit. /// </exception> public static ICheckLink <ICodeCheck <T> > ConsumesLessThan <T>( this ICodeCheck <T> check, double threshold, TimeUnit timeUnit) where T : RunTrace { var checker = ExtensibilityHelper.ExtractCodeChecker(check); var comparand = new Duration(checker.Value.TotalProcessorTime, timeUnit); var durationThreshold = new Duration(threshold, timeUnit); checker.ExecuteCheck( () => { if (comparand > durationThreshold) { var message = FluentMessage.BuildMessage( "The checked code consumed too much CPU time.") .For("cpu time") .On(comparand) .And.Expected(durationThreshold) .Comparison("less than") .ToString(); throw new FluentCheckException(message); } }, FluentMessage.BuildMessage("The checked code took too little cpu time to execute.").For("cpu time").On(comparand).And.Expected(durationThreshold).Comparison("more than").ToString()); return(new CheckLink <ICodeCheck <T> >(check)); }
/// <inheritdoc /> public ILambdaExceptionCheck <TE> DueTo <TE>() where TE : Exception { var innerException = this.Value.InnerException; while (innerException != null) { if (innerException.GetType() == typeof(TE)) { break; } innerException = innerException.InnerException; } if (innerException != null) { return(new LambdaExceptionCheck <TE>((TE)innerException)); } var message = FluentMessage .BuildMessage("The {0} did not contain an expected inner exception whereas it must.").For("exception") .On(ExceptionHelper.DumpInnerExceptionStackTrace(this.Value)).Label("The inner exception(s):").And .Expected(typeof(TE)).Label("The expected inner exception:").ToString(); throw new FluentCheckException(message); }
private static string IsEmptyImpl(string checkedValue, bool canBeNull, bool negated) { // special case if checkedvalue is null if (checkedValue == null) { if (canBeNull != negated) { return(null); } return(negated ? FluentMessage.BuildMessage("The {0} is null whereas it must have content.").For("string").ToString() : FluentMessage.BuildMessage("The {0} is null instead of being empty.").For("string").ToString()); } if (string.IsNullOrEmpty(checkedValue) != negated) { // success return(null); } if (negated) { return (FluentMessage.BuildMessage("The {0} is empty, whereas it must not.") .For("string") .ToString()); } return (FluentMessage.BuildMessage("The {0} is not empty or null.") .For("string") .On(checkedValue) .ToString()); }
private static string BuildHasSizeExceptionMessage(IEnumerable checkedEnumerable) { long itemsCount = checkedEnumerable.Cast <object>().LongCount(); var foundElementsNumberDescription = BuildElementNumberLiteral(itemsCount); return(FluentMessage.BuildMessage(string.Format("The {{0}} has {0} which is unexpected.", foundElementsNumberDescription.DoubleCurlyBraces())).For("enumerable").On(checkedEnumerable).ToString()); }
/// <summary> /// Checks that the enumerable contains all the values present in another enumerable, in any order. /// </summary> /// <param name="check">The fluent check to be extended.</param> /// <param name="otherEnumerable">The enumerable containing the expected values to be found.</param> /// <returns> /// A check link. /// </returns> /// <exception cref="FluentCheckException">The enumerable does not contain all the expected values present in the other enumerable.</exception> public static IExtendableCheckLink <IEnumerable> Contains(this ICheck <IEnumerable> check, IEnumerable otherEnumerable) { var checker = ExtensibilityHelper.ExtractChecker(check); checker.ExecuteCheck( () => { if (otherEnumerable == null) { return; } if (checker.Value == null) { var message = FluentMessage.BuildMessage("The {0} is null and thus, does not contain the given expected value(s).").For("enumerable").On(checker.Value).And.ExpectedValues(otherEnumerable).ToString(); throw new FluentCheckException(message); } var notFoundValues = ExtractNotFoundValues(checker.Value, otherEnumerable); if (notFoundValues.Count > 0) { var message = FluentMessage.BuildMessage(string.Format("The {{0}} does not contain the expected value(s):\n\t[{0}]", notFoundValues.ToEnumeratedString().DoubleCurlyBraces())).For("enumerable").On(checker.Value).And.ExpectedValues(otherEnumerable).ToString(); throw new FluentCheckException(message); } }, FluentMessage.BuildMessage("The {0} contains all the given values whereas it must not.").For("enumerable").On(checker.Value).And.ExpectedValues(otherEnumerable).ToString()); return(new ExtendableCheckLink <IEnumerable>(check, otherEnumerable)); }
/// <summary> /// Builds an error message. /// </summary> /// <param name="message">The message.</param> /// <returns>A <see cref="FluentMessage"/> instance.</returns> public FluentMessage BuildShortMessage(string message) { var result = FluentMessage.BuildMessage(message); result.For(typeof(T)); return(result); }
private static string EndsWithImpl(string checkedValue, string ends, bool negated) { // special case if checkedvalue is null if (checkedValue == null) { return(negated ? null : FluentMessage.BuildMessage("The {0} is null.").For("string").Expected(ends).Comparison("ends with").ToString()); } if (checkedValue.EndsWith(ends) != negated) { // success return(null); } if (negated) { return (FluentMessage.BuildMessage("The {0} ends with {1}, whereas it must not.") .For("string") .On(checkedValue) .And.Expected(ends) .Comparison("does not end with") .ToString()); } return (FluentMessage.BuildMessage("The {0}'s end is different from the {1}.") .For("string") .On(checkedValue) .And.Expected(ends) .Comparison("ends with") .ToString()); }
public static ICheckLink <ICheck <Sut> > Satisfies <Sut>(this ICheck <Sut> check, Func <Sut, bool> requirement) { // Every check method starts by extracting a checker instance from the check thanks to // the ExtensibilityHelper static class. var checker = ExtensibilityHelper.ExtractChecker(check); // Then, we let the checker's ExecuteCheck() method return the ICheckLink<ICheck<T>> result (with T as string here). // This method needs 2 arguments: // 1- a lambda that checks what's necessary, and throws a FluentAssertionException in case of failure // The exception message is usually fluently build with the FluentMessage.BuildMessage() static method. // // 2- a string containing the message for the exception to be thrown by the checker when // the check fails, in the case we were running the negated version. // // e.g.: var requirementName = GetNominalInfo(requirement); return(checker.ExecuteCheck( () => { if (!requirement(checker.Value)) { var errorMessage = FluentMessage.BuildMessage($"The {{0}} does not satisfy the requirement{requirementName}.").For(typeof(Sut).Name).On(checker.Value).ToString(); throw new FluentCheckException(errorMessage); } }, FluentMessage.BuildMessage($"The {{0}} satisifies the requirement {requirementName} whereas it must not.").For(typeof(Sut).Name).On(checker.Value).ToString())); }
public void InstanceValuesMustNotSupportWithType() { Check.ThatCode(() => { FluentMessage.BuildMessage("don't care").ExpectedType(typeof(string)).OfType(typeof(int)); }).Throws <NotSupportedException>(); }
public void InstanceValuesMustNotSupportHashCodes() { Check.ThatCode(() => { FluentMessage.BuildMessage("don't care").ExpectedType(typeof(string)).WithHashCode(); }).Throws <NotSupportedException>().WithMessage("Cannot use hash code for generic instance description!"); }
public void InstanceValuesMustNotSupportEnumerationFeatures() { Check.ThatCode(() => { FluentMessage.BuildMessage("don't care").ExpectedType(typeof(string)).WithEnumerableCount(0); }).Throws <NotSupportedException>(); }
/// <summary> /// Checks that a specific property of the considered Value has an expected value. /// </summary> /// <param name="propertyName">The name of the property to check on the considered Value.</param> /// <param name="propertyValue">The expected value for the property to check on the considered Value.</param> /// <returns> /// A check link. /// </returns> /// <Value cref="FluentCheckException">The code did not raised an Value of any type.</Value> public ICheckLink <ILambdaExceptionCheck <T> > WithProperty(string propertyName, object propertyValue) { var type = this.Value.GetType(); var property = type.GetProperty(propertyName); if (property == null) { var message = FluentMessage.BuildMessage(string.Format("There is no property [{0}] on exception type [{1}].", propertyName, type.Name)).ToString(); throw new FluentCheckException(message); } var value = property.GetValue(this.Value, null); if (!value.Equals(propertyValue)) { var message = FluentMessage .BuildMessage(string.Format("The property [{0}] of the {{0}} does not have the expected value.", propertyName.DoubleCurlyBraces())) .For("exception's property") .On(value) .And.WithGivenValue(propertyValue).ToString(); throw new FluentCheckException(message); } return(new CheckLink <ILambdaExceptionCheck <T> >(this)); }
/// <summary> /// Checks that the checked <see cref="char"/> is a letter. /// </summary> /// <param name="check">The chained fluent check.</param> /// <exception cref="FluentCheckException">The checked <see cref="char"/> is not a letter.</exception> /// <returns>A check link.</returns> public static ICheckLink<ICheck<char>> IsALetter(this ICheck<char> check) { // Every check method starts by extracting a checker instance from the check thanks to // the ExtensibilityHelper static class. var checker = ExtensibilityHelper.ExtractChecker(check); // Then, we let the checker's ExecuteCheck() method return the ICheckLink<ICheck<T>> result (with T as string here). // This method needs 2 arguments: // 1- a lambda that checks what's necessary, and throws a FluentAssertionException in case of failure // The exception message is usually fluently build with the FluentMessage.BuildMessage() static method. // // 2- a string containing the message for the exception to be thrown by the checker when // the check fails, in the case we were running the negated version. // // e.g.: return checker.ExecuteCheck( () => { if (!IsALetter(checker.Value)) { var errorMessage = FluentMessage.BuildMessage("The {0} is not a letter.").For("char").On(checker.Value).ToString(); throw new FluentCheckException(errorMessage); } }, FluentMessage.BuildMessage("The {0} is a letter whereas it must not.").For("char").On(checker.Value).ToString()); }
/// <summary> /// Checks that an inner exception is present within the outer exception stack trace. /// </summary> /// <returns> /// A check link. /// </returns> public ICheckLink <ILambdaExceptionCheck <T> > DueTo <E>() where E : Exception { var innerException = this.Value.InnerException; var dueToExceptionFound = false; while (innerException != null) { if (innerException.GetType() == typeof(E)) { dueToExceptionFound = true; break; } innerException = innerException.InnerException; } if (!dueToExceptionFound) { var message = FluentMessage.BuildMessage(string.Format("The {{0}} did not contain an expected inner exception whereas it must.")) .For("exception") .On(ExceptionHelper.DumpInnerExceptionStackTrace(this.Value)) .Label("The inner exception(s):") .And .Expected(typeof(E)).Label("The expected inner exception:") .ToString(); throw new FluentCheckException(message); } return(new CheckLink <ILambdaExceptionCheck <T> >(this)); }
/// <summary> /// Checks that the actual duration is less (strictly) than a comparand. /// </summary> /// <param name="check">The fluent check to be extended.</param> /// <param name="comparand">The value to compare to.</param> /// <returns>A check link.</returns> /// <exception cref="FluentCheckException">The actual value is not less than the provided comparand.</exception> public static ICheckLink <ICheck <TimeSpan> > IsLessThan(this ICheck <TimeSpan> check, TimeSpan comparand) { var checker = ExtensibilityHelper.ExtractChecker(check); var unit = TimeHelper.DiscoverUnit(comparand); var testedDuration = new Duration(checker.Value, unit); var expected = new Duration(comparand, unit); var notMessage = FluentMessage.BuildMessage("The {0} is not more than the limit.") .On(testedDuration) .And.Expected(expected) .Comparison("more than or equal to"); var message = FluentMessage.BuildMessage("The {0} is more than the limit.") .On(testedDuration) .And.Expected(expected).Comparison("less than"); return(checker.ExecuteCheck( () => { if (testedDuration >= expected) { throw new FluentCheckException(message.ToString()); } }, notMessage.ToString())); }
/// <summary> /// Checks that the actual duration is equal to a target duration. /// </summary> /// <param name="check">The fluent check to be extended.</param> /// <param name="comparand">The duration to be compared to.</param> /// <returns>A check link.</returns> /// /// <exception cref="FluentCheckException">The actual value is not equal to the target duration.</exception> public static ICheckLink <ICheck <TimeSpan> > IsEqualTo(this ICheck <TimeSpan> check, TimeSpan comparand) { var checker = ExtensibilityHelper.ExtractChecker(check); TimeUnit unit = TimeHelper.DiscoverUnit(comparand); var testedDuration = new Duration(checker.Value, unit); var expected = new Duration(comparand, unit); var message = FluentMessage.BuildMessage("The {0} is different from the {1}.") .On(testedDuration) .And.Expected(expected); var notMessage = FluentMessage.BuildMessage("The {0} is the same than {1}.") .On(testedDuration) .And.Expected(expected) .Comparison("different than"); return(checker.ExecuteCheck( () => { if (checker.Value != comparand) { throw new FluentCheckException(message.ToString()); } }, notMessage.ToString())); }
/// <summary> /// Checks that a comparable checked value is after another given value. /// </summary> /// <param name="checkedValue">The checked value.</param> /// <param name="givenValue">The other given value.</param> /// <exception cref="NFluent.FluentCheckException">The checked value is not after the given value.</exception> public static void IsAfter(IComparable checkedValue, IComparable givenValue) { if (checkedValue == null || checkedValue.CompareTo(givenValue) <= 0) { throw new FluentCheckException(FluentMessage.BuildMessage("The {0} is not after the reference value.").On(checkedValue).And.Expected(givenValue).Comparison("after").ToString()); } }
private static string MatchesImpl(string checkedValue, string regExp, bool negated) { // special case if checkedvalue is null if (checkedValue == null) { return(negated ? null : FluentMessage.BuildMessage("The {0} is null.").For("string").Expected(regExp).Comparison("matches").ToString()); } Regex exp = new Regex(regExp); if (exp.IsMatch(checkedValue) != negated) { // success return(null); } if (negated) { return (FluentMessage.BuildMessage("The {0} matches {1}, whereas it must not.") .For("string") .On(checkedValue) .And.Expected(regExp) .Comparison("does not match") .ToString()); } return (FluentMessage.BuildMessage("The {0} does not match the {1}.") .For("string") .On(checkedValue) .And.Expected(regExp) .Comparison("matches") .ToString()); }
public void ShouldPermitChangingMainMessage() { var message = FluentMessage.BuildMessage("The {0} is before the {1} whereas it must not."); message.ChangeMessageTo("The {0} is not before the {1}."); Assert.AreEqual(NewLine + "The checked value is not before the expected one.", message.ToString()); }
private static string BuildExceptionMessageForContainsExactly(IEnumerable checkedValue, IEnumerable enumerable) { return(FluentMessage.BuildMessage("The {0} contains exactly the given values whereas it must not.") .For("enumerable") .On(checkedValue) .WithEnumerableCount(checkedValue.Count()) .ToString()); }
public void CheckedBlockTest() { var test = DateTime.Today; var message = FluentMessage.BuildMessage("The {0} is below.").On(test).ToString(); var lines = message.Split('\n'); Assert.AreEqual(4, lines.Length); Assert.IsTrue(lines[1].Contains("checked")); }
public void HowGivenValueWorks() { var message = FluentMessage.BuildMessage("The {0} is before the {1} whereas it must not.") .For("date time") .On("portna") .And.WithGivenValue("ouaq").ToString(); Assert.AreEqual(NewLine + "The checked date time is before the given one whereas it must not." + NewLine + "The checked date time:" + NewLine + "\t[\"portna\"]" + NewLine + "The expected date time:" + NewLine + "\t[\"ouaq\"]", message); }