From 9197d214d7f8c119bc6161bc615c9fb4e9668c3a Mon Sep 17 00:00:00 2001 From: jnyrup Date: Fri, 26 Jul 2019 19:07:04 +0200 Subject: [PATCH] Null guards on funcs and expressions --- .../Collections/CollectionAssertions.cs | 10 ++ .../GenericCollectionAssertions.cs | 4 + .../SelfReferencingCollectionAssertions.cs | 8 + .../Equivalency/ConversionSelector.cs | 5 + .../EventRaisingExtensions.cs | 3 + .../Execution/GivenSelector.cs | 5 + .../Specialized/ExceptionAssertions.cs | 2 + .../Types/MemberInfoAssertions.cs | 4 + .../Types/MethodInfoSelectorAssertions.cs | 4 + Src/FluentAssertions/Types/TypeAssertions.cs | 8 + .../Types/TypeSelectorAssertions.cs | 8 + Tests/Shared.Specs/BasicEquivalencySpecs.cs | 46 +++++ .../Shared.Specs/CollectionAssertionSpecs.cs | 20 +++ Tests/Shared.Specs/EventAssertionSpecs.cs | 26 +++ Tests/Shared.Specs/ExceptionAssertionSpecs.cs | 21 +++ ...GenericCollectionAssertionOfStringSpecs.cs | 22 +++ .../GenericCollectionAssertionsSpecs.cs | 100 +++++++++++ .../Shared.Specs/MethodInfoAssertionSpecs.cs | 40 +++++ .../MethodInfoSelectorAssertionSpecs.cs | 42 +++++ Tests/Shared.Specs/TypeAssertionSpecs.cs | 168 ++++++++++++++++++ 20 files changed, 546 insertions(+) diff --git a/Src/FluentAssertions/Collections/CollectionAssertions.cs b/Src/FluentAssertions/Collections/CollectionAssertions.cs index 8b8e9901fb..e50e28760c 100644 --- a/Src/FluentAssertions/Collections/CollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/CollectionAssertions.cs @@ -242,6 +242,8 @@ public AndConstraint Equal(IEnumerable expected, string because = " protected void AssertSubjectEquality(IEnumerable expectation, Func equalityComparison, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison)); + bool subjectIsNull = ReferenceEquals(Subject, null); bool expectationIsNull = expectation is null; if (subjectIsNull && expectationIsNull) @@ -1416,6 +1418,8 @@ public AndConstraint StartWith(object element, string because = "", protected void AssertCollectionStartsWith(IEnumerable actualItems, TExpected[] expected, Func equalityComparison, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison)); + Execute.Assertion .BecauseOf(because, becauseArgs) .WithExpectation("Expected {context:collection} to start with {0}{reason}, ", expected) @@ -1431,6 +1435,8 @@ protected void AssertCollectionStartsWith(IEnumerable(IEnumerable actualItems, ICollection expected, Func equalityComparison, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison)); + Execute.Assertion .BecauseOf(because, becauseArgs) .WithExpectation("Expected {context:collection} to start with {0}{reason}, ", expected) @@ -1466,6 +1472,8 @@ public AndConstraint EndWith(object element, string because = "", p protected void AssertCollectionEndsWith(IEnumerable actual, TExpected[] expected, Func equalityComparison, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison)); + Execute.Assertion .BecauseOf(because, becauseArgs) .WithExpectation("Expected {context:collection} to end with {0}{reason}, ", expected) @@ -1486,6 +1494,8 @@ protected void AssertCollectionEndsWith(IEnumerable protected void AssertCollectionEndsWith(IEnumerable actual, ICollection expected, Func equalityComparison, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(equalityComparison, nameof(equalityComparison)); + Execute.Assertion .BecauseOf(because, becauseArgs) .WithExpectation("Expected {context:collection} to end with {0}{reason}, ", expected) diff --git a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs index b37573d82b..0f8574bc3e 100644 --- a/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/GenericCollectionAssertions.cs @@ -34,6 +34,8 @@ public GenericCollectionAssertions(IEnumerable actualValue) public AndConstraint> NotContainNulls(Expression> predicate, string because = "", params object[] becauseArgs) where TKey : class { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + if (Subject is null) { Execute.Assertion @@ -72,6 +74,8 @@ public AndConstraint> NotContainNulls(Expre /// public AndConstraint> OnlyHaveUniqueItems(Expression> predicate, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + if (Subject is null) { Execute.Assertion diff --git a/Src/FluentAssertions/Collections/SelfReferencingCollectionAssertions.cs b/Src/FluentAssertions/Collections/SelfReferencingCollectionAssertions.cs index 6bbd1b7489..f835a73051 100644 --- a/Src/FluentAssertions/Collections/SelfReferencingCollectionAssertions.cs +++ b/Src/FluentAssertions/Collections/SelfReferencingCollectionAssertions.cs @@ -447,6 +447,8 @@ public AndConstraint Contain(IEnumerable expectedItemsList, /// public AndWhichConstraint Contain(Expression> predicate, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + if (Subject is null) { Execute.Assertion @@ -478,6 +480,8 @@ public AndWhichConstraint Contain(Expression> pred public AndConstraint OnlyContain( Expression> predicate, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + Func compiledPredicate = predicate.Compile(); Execute.Assertion @@ -555,6 +559,8 @@ public AndConstraint NotContain(IEnumerable unexpectedItemsList, /// public AndConstraint NotContain(Expression> predicate, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + if (Subject is null) { Execute.Assertion @@ -624,6 +630,8 @@ public AndWhichConstraint ContainSingle(string because = "", par public AndWhichConstraint ContainSingle(Expression> predicate, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + string expectationPrefix = string.Format("Expected {{context:collection}} to contain a single item matching {0}{{reason}}, ", predicate.Body); diff --git a/Src/FluentAssertions/Equivalency/ConversionSelector.cs b/Src/FluentAssertions/Equivalency/ConversionSelector.cs index 4d168721e0..b0cf775ee9 100644 --- a/Src/FluentAssertions/Equivalency/ConversionSelector.cs +++ b/Src/FluentAssertions/Equivalency/ConversionSelector.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Linq.Expressions; using System.Text; +using FluentAssertions.Common; namespace FluentAssertions.Equivalency { @@ -33,6 +34,8 @@ public void IncludeAll() public void Include(Expression> predicate) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + inclusions.Add(new ConversionSelectorRule( predicate.Compile(), $"Try conversion of member {predicate.Body}. ")); @@ -40,6 +43,8 @@ public void Include(Expression> predicate) public void Exclude(Expression> predicate) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + exclusions.Add(new ConversionSelectorRule( predicate.Compile(), $"Do not convert member {predicate.Body}.")); diff --git a/Src/FluentAssertions/EventRaisingExtensions.cs b/Src/FluentAssertions/EventRaisingExtensions.cs index fbbcb9130e..59aa5c35eb 100644 --- a/Src/FluentAssertions/EventRaisingExtensions.cs +++ b/Src/FluentAssertions/EventRaisingExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Linq.Expressions; +using FluentAssertions.Common; using FluentAssertions.Events; using FluentAssertions.Execution; @@ -39,6 +40,8 @@ public static IEventRecorder WithSender(this IEventRecorder eventRecorder, objec /// public static IEventRecorder WithArgs(this IEventRecorder eventRecorder, Expression> predicate) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + Func compiledPredicate = predicate.Compile(); if (!eventRecorder.First().Parameters.OfType().Any()) diff --git a/Src/FluentAssertions/Execution/GivenSelector.cs b/Src/FluentAssertions/Execution/GivenSelector.cs index cad3b61ebb..47869a7e0f 100644 --- a/Src/FluentAssertions/Execution/GivenSelector.cs +++ b/Src/FluentAssertions/Execution/GivenSelector.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using FluentAssertions.Common; namespace FluentAssertions.Execution { @@ -40,6 +41,8 @@ public GivenSelector(Func selector, bool predecessorSucceeded, AssertionScope /// public GivenSelector ForCondition(Func predicate) { + Guard.ThrowIfArgumentIsNull(predicate, nameof(predicate)); + predecessor.ForCondition(predicate(subject)); return this; @@ -57,6 +60,8 @@ public GivenSelector ForCondition(Func predicate) /// public GivenSelector Given(Func selector) { + Guard.ThrowIfArgumentIsNull(selector, nameof(selector)); + return new GivenSelector(() => selector(subject), predecessorSucceeded, predecessor); } diff --git a/Src/FluentAssertions/Specialized/ExceptionAssertions.cs b/Src/FluentAssertions/Specialized/ExceptionAssertions.cs index 5f64f92f85..d20ab64084 100644 --- a/Src/FluentAssertions/Specialized/ExceptionAssertions.cs +++ b/Src/FluentAssertions/Specialized/ExceptionAssertions.cs @@ -147,6 +147,8 @@ public virtual ExceptionAssertions WithInnerExceptionExactly Where(Expression> exceptionExpression, string because = "", params object[] becauseArgs) { + Guard.ThrowIfArgumentIsNull(exceptionExpression, nameof(exceptionExpression)); + Func condition = exceptionExpression.Compile(); Execute.Assertion .ForCondition(condition(SingleSubject)) diff --git a/Src/FluentAssertions/Types/MemberInfoAssertions.cs b/Src/FluentAssertions/Types/MemberInfoAssertions.cs index a82934d8b4..77dfab5cba 100644 --- a/Src/FluentAssertions/Types/MemberInfoAssertions.cs +++ b/Src/FluentAssertions/Types/MemberInfoAssertions.cs @@ -79,6 +79,8 @@ public AndWhichConstraint, TAttribut string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + string failureMessage = string.Format("Expected {0} {1}" + " to be decorated with {2}{{reason}}, but that attribute was not found.", Identifier, SubjectDescription, typeof(TAttribute)); @@ -112,6 +114,8 @@ public AndConstraint NotBeDecoratedWith( string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + string failureMessage = string.Format("Expected {0} {1}" + " to not be decorated with {2}{{reason}}, but that attribute was found.", Identifier, SubjectDescription, typeof(TAttribute)); diff --git a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs index 4c8ab9b438..5e2adf5416 100644 --- a/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/MethodInfoSelectorAssertions.cs @@ -137,6 +137,8 @@ public AndConstraint BeDecoratedWith( Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + IEnumerable methodsWithoutAttribute = GetMethodsWithout(isMatchingAttributePredicate); string failureMessage = @@ -186,6 +188,8 @@ public AndConstraint NotBeDecoratedWith> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + IEnumerable methodsWithAttribute = GetMethodsWith(isMatchingAttributePredicate); string failureMessage = diff --git a/Src/FluentAssertions/Types/TypeAssertions.cs b/Src/FluentAssertions/Types/TypeAssertions.cs index 023786cb99..df573d3574 100644 --- a/Src/FluentAssertions/Types/TypeAssertions.cs +++ b/Src/FluentAssertions/Types/TypeAssertions.cs @@ -249,6 +249,8 @@ public AndConstraint BeDecoratedWith( Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + BeDecoratedWith(because, becauseArgs); Execute.Assertion @@ -300,6 +302,8 @@ public AndConstraint BeDecoratedWithOrInherit( Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + BeDecoratedWithOrInherit(because, becauseArgs); Execute.Assertion @@ -351,6 +355,8 @@ public AndConstraint NotBeDecoratedWith( Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + Execute.Assertion .ForCondition(!Subject.HasMatchingAttribute(isMatchingAttributePredicate)) .BecauseOf(because, becauseArgs) @@ -400,6 +406,8 @@ public AndConstraint NotBeDecoratedWithOrInherit( Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + Execute.Assertion .ForCondition(!Subject.HasMatchingAttribute(isMatchingAttributePredicate, true)) .BecauseOf(because, becauseArgs) diff --git a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs index c6781c0b79..fd9ce7d3f3 100644 --- a/Src/FluentAssertions/Types/TypeSelectorAssertions.cs +++ b/Src/FluentAssertions/Types/TypeSelectorAssertions.cs @@ -75,6 +75,8 @@ public AndConstraint BeDecoratedWith( Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + Type[] typesWithoutMatchingAttribute = Subject .Where(type => !type.HasMatchingAttribute(isMatchingAttributePredicate)) .ToArray(); @@ -139,6 +141,8 @@ public AndConstraint BeDecoratedWithOrInherit> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + Type[] typesWithoutMatchingAttribute = Subject .Where(type => !type.HasMatchingAttribute(isMatchingAttributePredicate, true)) .ToArray(); @@ -203,6 +207,8 @@ public AndConstraint NotBeDecoratedWith( Expression> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + Type[] typesWithMatchingAttribute = Subject .Where(type => type.HasMatchingAttribute(isMatchingAttributePredicate)) .ToArray(); @@ -267,6 +273,8 @@ public AndConstraint NotBeDecoratedWithOrInherit> isMatchingAttributePredicate, string because = "", params object[] becauseArgs) where TAttribute : Attribute { + Guard.ThrowIfArgumentIsNull(isMatchingAttributePredicate, nameof(isMatchingAttributePredicate)); + Type[] typesWithMatchingAttribute = Subject .Where(type => type.HasMatchingAttribute(isMatchingAttributePredicate, true)) .ToArray(); diff --git a/Tests/Shared.Specs/BasicEquivalencySpecs.cs b/Tests/Shared.Specs/BasicEquivalencySpecs.cs index 6215e3e3fe..6d0e55c58e 100644 --- a/Tests/Shared.Specs/BasicEquivalencySpecs.cs +++ b/Tests/Shared.Specs/BasicEquivalencySpecs.cs @@ -2566,6 +2566,29 @@ public void When_an_int_is_compared_equivalent_to_a_string_representing_the_numb act.Should().NotThrow(); } + [Fact] + public void When_injecting_a_null_predicate_into_WithAutoConversionFor_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + var subject = new object(); + + var expectation = new object(); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => subject.Should().BeEquivalentTo(expectation, + options => options.WithAutoConversionFor(predicate: null)); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void When_only_a_single_property_is_and_can_be_converted_but_the_other_one_doesnt_match_it_should_throw() { @@ -2626,6 +2649,29 @@ public void When_only_a_single_property_is_converted_and_the_other_matches_it_sh act.Should().NotThrow(); } + [Fact] + public void When_injecting_a_null_predicate_into_WithoutAutoConversionFor_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + var subject = new object(); + + var expectation = new object(); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => subject.Should().BeEquivalentTo(expectation, + options => options.WithoutAutoConversionFor(predicate: null)); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void When_a_specific_mismatching_property_is_excluded_from_conversion_it_should_throw() { diff --git a/Tests/Shared.Specs/CollectionAssertionSpecs.cs b/Tests/Shared.Specs/CollectionAssertionSpecs.cs index 78d97e2268..15da4640a2 100644 --- a/Tests/Shared.Specs/CollectionAssertionSpecs.cs +++ b/Tests/Shared.Specs/CollectionAssertionSpecs.cs @@ -2982,6 +2982,26 @@ public void When_collection_contains_an_unexpected_item_it_should_throw() "Expected collection {1, 2, 3} to not contain element 1 because we don't like it, but found it anyhow."); } + [Fact] + public void When_injecting_a_null_predicate_into_NotContain_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + IEnumerable collection = new int[] { }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => collection.Should().NotContain(predicate: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void When_collection_does_contain_an_unexpected_item_matching_a_predicate_it_should_throw() { diff --git a/Tests/Shared.Specs/EventAssertionSpecs.cs b/Tests/Shared.Specs/EventAssertionSpecs.cs index f2aa2b2c74..21f55be740 100644 --- a/Tests/Shared.Specs/EventAssertionSpecs.cs +++ b/Tests/Shared.Specs/EventAssertionSpecs.cs @@ -205,6 +205,32 @@ public void When_the_event_sender_is_the_expected_object_it_should_not_throw() } } + [Fact] + public void When_injecting_a_null_predicate_into_WithArgs_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //---------------------------------------------------------------------------------------------------------- + var subject = new EventRaisingClass(); + using (var monitor = subject.Monitor()) + { + subject.RaiseNonConventionalEvent("first argument", 2, "third argument"); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => monitor.Should() + .Raise("NonConventionalEvent") + .WithArgs(predicate: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + } + [Fact] public void When_the_event_parameters_dont_match_it_should_throw() { diff --git a/Tests/Shared.Specs/ExceptionAssertionSpecs.cs b/Tests/Shared.Specs/ExceptionAssertionSpecs.cs index 68d6b3543e..75fd93f591 100644 --- a/Tests/Shared.Specs/ExceptionAssertionSpecs.cs +++ b/Tests/Shared.Specs/ExceptionAssertionSpecs.cs @@ -723,6 +723,27 @@ public void When_an_inner_exception_matches_exactly_it_should_allow_chaining_mor .Where(i => i.Message == "InnerMessage"); } + [Fact] + public void When_injecting_a_null_predicate_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + Action act = () => throw new Exception(); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act2 = () => act.Should().Throw() + .Where(exceptionExpression: null); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + act2.Should().ThrowExactly() + .Which.ParamName.Should().Be("exceptionExpression"); + } + #endregion #region Miscellaneous diff --git a/Tests/Shared.Specs/GenericCollectionAssertionOfStringSpecs.cs b/Tests/Shared.Specs/GenericCollectionAssertionOfStringSpecs.cs index b4383a3c23..133adb4e12 100644 --- a/Tests/Shared.Specs/GenericCollectionAssertionOfStringSpecs.cs +++ b/Tests/Shared.Specs/GenericCollectionAssertionOfStringSpecs.cs @@ -459,6 +459,28 @@ public void When_any_item_does_not_match_according_to_a_predicate_it_should_thro .WithMessage("Expected*equal to*, but*differs at index 3."); } + [Fact] + public void When_injecting_a_null_comparer_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + var actual = new List(); + var expected = new List(); + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action action = () => actual.Should().Equal(expected, equalityComparison: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + action + .Should().ThrowExactly() + .Which.ParamName.Should().Be("equalityComparison"); + } + [Fact] public void When_asserting_a_string_collection_contains_an_element_it_should_allow_specifying_the_reason_via_named_parameter() diff --git a/Tests/Shared.Specs/GenericCollectionAssertionsSpecs.cs b/Tests/Shared.Specs/GenericCollectionAssertionsSpecs.cs index 6f7923f3c2..d2245803af 100644 --- a/Tests/Shared.Specs/GenericCollectionAssertionsSpecs.cs +++ b/Tests/Shared.Specs/GenericCollectionAssertionsSpecs.cs @@ -30,6 +30,26 @@ public void When_asserting_equality_with_a_collection_built_from_params_argument #region (Not) Contain + [Fact] + public void When_injecting_a_null_predicate_into_Contain_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + IEnumerable collection = new int[] { }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => collection.Should().Contain(predicate: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void When_collection_does_not_contain_an_expected_item_matching_a_predicate_it_should_throw() { @@ -268,6 +288,26 @@ public void When_a_collection_does_contain_the_combination_of_a_collection_and_a #region Only Contain (Predicate) + [Fact] + public void When_injecting_a_null_predicate_into_OnlyContain_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + IEnumerable collection = new int[] { }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => collection.Should().OnlyContain(predicate: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void When_a_collection_contains_items_not_matching_a_predicate_it_should_throw() { @@ -335,6 +375,26 @@ public void When_a_collection_contains_only_items_matching_a_predicate_it_should #region Contain Single + [Fact] + public void When_injecting_a_null_predicate_into_ContainSingle_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + IEnumerable collection = new int[] { }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => collection.Should().ContainSingle(predicate: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void When_a_collection_contains_a_single_item_matching_a_predicate_it_should_succeed() { @@ -1066,6 +1126,26 @@ private class SomeClass #region Not Contain Nulls (Predicate) + [Fact] + public void When_injecting_a_null_predicate_into_NotContainNulls_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + IEnumerable collection = new SomeClass[] { }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => collection.Should().NotContainNulls(predicate: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void When_collection_does_not_contain_nulls_it_should_not_throw() { @@ -1157,6 +1237,26 @@ public void When_asserting_collection_to_not_contain_nulls_but_collection_is_nul #region Only Have Unique Items (Predicate) + [Fact] + public void When_injecting_a_null_predicate_into_OnlyHaveUniqueItems_it_should_throw() + { + //----------------------------------------------------------------------------------------------------------- + // Arrange + //----------------------------------------------------------------------------------------------------------- + IEnumerable collection = new SomeClass[] { }; + + //----------------------------------------------------------------------------------------------------------- + // Act + //----------------------------------------------------------------------------------------------------------- + Action act = () => collection.Should().OnlyHaveUniqueItems(predicate: null); + + //----------------------------------------------------------------------------------------------------------- + // Assert + //----------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("predicate"); + } + [Fact] public void Should_succeed_when_asserting_collection_with_unique_items_contains_only_unique_items() { diff --git a/Tests/Shared.Specs/MethodInfoAssertionSpecs.cs b/Tests/Shared.Specs/MethodInfoAssertionSpecs.cs index f0d27bc859..67384e0b74 100644 --- a/Tests/Shared.Specs/MethodInfoAssertionSpecs.cs +++ b/Tests/Shared.Specs/MethodInfoAssertionSpecs.cs @@ -319,6 +319,26 @@ public void When_asserting_a_method_is_decorated_with_an_attribute_but_it_is_not " but that attribute was not found."); } + [Fact] + public void When_injecting_a_null_predicate_into_BeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + MethodInfo methodInfo = typeof(ClassWithAllMethodsDecoratedWithDummyAttribute).GetParameterlessMethod("PublicDoNothing"); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => methodInfo.Should().BeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_asserting_a_method_is_decorated_with_attribute_matching_a_predicate_and_it_is_it_succeeds() { @@ -561,6 +581,26 @@ public void When_asserting_a_method_is_not_decorated_with_attribute_matching_a_p act.Should().NotThrow(); } + [Fact] + public void When_injecting_a_null_predicate_into_NotBeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + MethodInfo methodInfo = typeof(ClassWithAllMethodsDecoratedWithDummyAttribute).GetParameterlessMethod("PublicDoNothing"); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => methodInfo.Should().NotBeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_asserting_a_method_is_not_decorated_with_an_attribute_matching_a_predicate_but_it_is_it_throws_with_a_useful_message() { diff --git a/Tests/Shared.Specs/MethodInfoSelectorAssertionSpecs.cs b/Tests/Shared.Specs/MethodInfoSelectorAssertionSpecs.cs index 71e7ac93ab..21bcc237f7 100644 --- a/Tests/Shared.Specs/MethodInfoSelectorAssertionSpecs.cs +++ b/Tests/Shared.Specs/MethodInfoSelectorAssertionSpecs.cs @@ -139,6 +139,27 @@ public void When_asserting_methods_are_not_virtual_but_virtual_methods_are_found "*ClassWithAllMethodsVirtual.ProtectedVirtualDoNothing*"); } + [Fact] + public void When_injecting_a_null_predicate_into_BeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + var methodSelector = new MethodInfoSelector(typeof(ClassWithAllMethodsDecoratedWithDummyAttribute)); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => + methodSelector.Should().BeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_asserting_methods_are_decorated_with_attribute_and_they_are_it_should_succeed() { @@ -207,6 +228,27 @@ public void When_asserting_methods_are_decorated_with_attribute_but_they_are_not "Void FluentAssertions.Specs.ClassWithMethodsThatAreNotDecoratedWithDummyAttribute.PrivateDoNothing"); } + [Fact] + public void When_injecting_a_null_predicate_into_NotBeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + var methodSelector = new MethodInfoSelector(typeof(ClassWithMethodsThatAreNotDecoratedWithDummyAttribute)); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => + methodSelector.Should().NotBeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_asserting_methods_are_not_decorated_with_attribute_and_they_are_not_it_should_succeed() { diff --git a/Tests/Shared.Specs/TypeAssertionSpecs.cs b/Tests/Shared.Specs/TypeAssertionSpecs.cs index 0ebca24447..cd53a82f81 100644 --- a/Tests/Shared.Specs/TypeAssertionSpecs.cs +++ b/Tests/Shared.Specs/TypeAssertionSpecs.cs @@ -1091,6 +1091,27 @@ public void When_type_is_not_decorated_with_expected_attribute_it_fails_with_a_u "was not found."); } + [Fact] + public void When_injecting_a_null_predicate_into_BeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + Type typeWithAttribute = typeof(ClassWithAttribute); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => + typeWithAttribute.Should().BeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_type_is_decorated_with_expected_attribute_with_the_expected_properties_it_succeeds() { @@ -1188,6 +1209,27 @@ public void When_asserting_a_selection_of_non_decorated_types_is_decorated_with_ "*OtherClassWithoutAttribute*."); } + [Fact] + public void When_injecting_a_null_predicate_into_TypeSelector_BeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + var types = new TypeSelector(typeof(ClassWithAttribute)); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => types.Should() + .BeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_asserting_a_selection_of_types_with_unexpected_attribute_property_it_fails() { @@ -1288,6 +1330,27 @@ public void When_type_does_not_inherit_expected_attribute_it_fails_with_a_useful "was not found."); } + [Fact] + public void When_injecting_a_null_predicate_into_BeDecoratedWithOrInherit_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + Type typeWithAttribute = typeof(ClassWithInheritedAttribute); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => typeWithAttribute.Should() + .BeDecoratedWithOrInherit(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_type_inherits_expected_attribute_with_the_expected_properties_it_succeeds() { @@ -1385,6 +1448,27 @@ public void When_asserting_a_selection_of_non_decorated_types_inheriting_an_attr "*OtherClassWithoutAttribute*."); } + [Fact] + public void When_injecting_a_null_predicate_into_TypeSelector_BeDecoratedWithOrInherit_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + var types = new TypeSelector(typeof(ClassWithAttribute)); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => types.Should() + .BeDecoratedWithOrInherit(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_asserting_a_selection_of_types_with_some_inheriting_attributes_with_unexpected_attribute_property_it_fails() { @@ -1485,6 +1569,27 @@ public void When_type_is_decorated_with_unexpected_attribute_it_fails_with_a_use "*DummyClassAttribute*because we want to test the error message*attribute was found."); } + [Fact] + public void When_injecting_a_null_predicate_into_NotBeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + Type typeWithoutAttribute = typeof(ClassWithAttribute); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => typeWithoutAttribute.Should() + .NotBeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_type_is_not_decorated_with_unexpected_attribute_with_the_expected_properties_it_succeeds() { @@ -1580,6 +1685,27 @@ public void When_asserting_a_selection_of_decorated_types_is_not_decorated_with_ "*because we do*attribute was found*ClassWithAttribute*"); } + [Fact] + public void When_injecting_a_null_predicate_into_TypeSelector_NotBeDecoratedWith_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + var types = new TypeSelector(typeof(ClassWithAttribute)); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => types.Should() + .NotBeDecoratedWith(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_asserting_a_selection_of_types_with_unexpected_attribute_and_unexpected_attribute_property_it_fails() { @@ -1676,6 +1802,27 @@ public void When_type_inherits_unexpected_attribute_it_fails_with_a_useful_messa "*DummyClassAttribute*because we want to test the error message*attribute was found."); } + [Fact] + public void When_injecting_a_null_predicate_into_NotBeDecoratedWithOrInherit_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + Type typeWithoutAttribute = typeof(ClassWithInheritedAttribute); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => typeWithoutAttribute.Should() + .NotBeDecoratedWithOrInherit(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + [Fact] public void When_type_does_not_inherit_unexpected_attribute_with_the_expected_properties_it_succeeds() { @@ -1771,6 +1918,27 @@ public void When_asserting_a_selection_of_decorated_types_does_not_inherit_an_at "*because we do*attribute was found*ClassWithInheritedAttribute*"); } + [Fact] + public void When_injecting_a_null_predicate_into_TypeSelector_NotBeDecoratedWithOrInherit_it_should_throw() + { + //------------------------------------------------------------------------------------------------------------------- + // Arrange + //------------------------------------------------------------------------------------------------------------------- + var types = new TypeSelector(typeof(ClassWithAttribute)); + + //------------------------------------------------------------------------------------------------------------------- + // Act + //------------------------------------------------------------------------------------------------------------------- + Action act = () => types.Should() + .NotBeDecoratedWithOrInherit(isMatchingAttributePredicate: null); + + //------------------------------------------------------------------------------------------------------------------- + // Assert + //------------------------------------------------------------------------------------------------------------------- + act.Should().ThrowExactly() + .Which.ParamName.Should().Be("isMatchingAttributePredicate"); + } + #endregion #region BeSealed