Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase mutation score #1211

Merged
merged 1 commit into from Dec 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 10 additions & 16 deletions Src/FluentAssertions/Primitives/StringAssertions.cs
Expand Up @@ -276,23 +276,20 @@ public AndConstraint<StringAssertions> MatchRegex([RegexPattern] string regularE
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:string} to match regex {0}{reason}, but it was <null>.", regularExpression);

bool isMatch = false;
try
{
isMatch = Regex.IsMatch(Subject, regularExpression);
Execute.Assertion
.ForCondition(Regex.IsMatch(Subject, regularExpression))
.BecauseOf(because, becauseArgs)
.UsingLineBreaks
.FailWith("Expected {context:string} to match regex {0}{reason}, but {1} does not match.", regularExpression, Subject);
}
catch (ArgumentException)
{
Execute.Assertion
.FailWith("Cannot match {context:string} against {0} because it is not a valid regular expression.", regularExpression);
}

Execute.Assertion
.ForCondition(isMatch)
.BecauseOf(because, becauseArgs)
.UsingLineBreaks
.FailWith("Expected {context:string} to match regex {0}{reason}, but {1} does not match.", regularExpression, Subject);

return new AndConstraint<StringAssertions>(this);
}

Expand All @@ -319,23 +316,20 @@ public AndConstraint<StringAssertions> NotMatchRegex([RegexPattern] string regul
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:string} to not match regex {0}{reason}, but it was <null>.", regularExpression);

bool isMatch = false;
try
{
isMatch = Regex.IsMatch(Subject, regularExpression);
Execute.Assertion
.ForCondition(!Regex.IsMatch(Subject, regularExpression))
.BecauseOf(because, becauseArgs)
.UsingLineBreaks
.FailWith("Did not expect {context:string} to match regex {0}{reason}, but {1} matches.", regularExpression, Subject);
}
catch (ArgumentException)
{
Execute.Assertion.FailWith("Cannot match {context:string} against {0} because it is not a valid regular expression.",
regularExpression);
}

Execute.Assertion
.ForCondition(!isMatch)
.BecauseOf(because, becauseArgs)
.UsingLineBreaks
.FailWith("Did not expect {context:string} to match regex {0}{reason}, but {1} matches.", regularExpression, Subject);

return new AndConstraint<StringAssertions>(this);
}

Expand Down
36 changes: 36 additions & 0 deletions Tests/Shared.Specs/AsyncFunctionExceptionAssertionSpecs.cs
Expand Up @@ -1032,6 +1032,24 @@ public void When_wait_time_is_negative_for_async_func_executed_with_wait_it_shou
.WithMessage("* value of waitTime must be non-negative*");
}

[Fact]
public void When_wait_time_is_zero_for_async_func_executed_with_wait_it_should_not_throw()
{
// Arrange
var waitTime = 0.Milliseconds();
var pollInterval = 10.Milliseconds();

var clock = new FakeClock();
var asyncObject = new AsyncClass();
Func<Task> someFunc = () => asyncObject.SucceedAsync();

// Act
Action act = () => someFunc.Should(clock).NotThrowAfter(waitTime, pollInterval);

// Assert
act.Should().NotThrow();
}

[Fact]
public void When_poll_interval_is_negative_for_async_func_executed_with_wait_it_should_throw()
{
Expand All @@ -1050,6 +1068,24 @@ public void When_poll_interval_is_negative_for_async_func_executed_with_wait_it_
.WithMessage("* value of pollInterval must be non-negative*");
}

[Fact]
public void When_poll_interval_is_zero_for_async_func_executed_with_wait_it_should_not_throw()
{
// Arrange
var waitTime = 10.Milliseconds();
var pollInterval = 0.Milliseconds();

var clock = new FakeClock();
var asyncObject = new AsyncClass();
Func<Task> someFunc = () => asyncObject.SucceedAsync();

// Act
Action act = () => someFunc.Should(clock).NotThrowAfter(waitTime, pollInterval);

// Assert
act.Should().NotThrow();
}

[Fact]
public void
When_no_exception_should_be_thrown_for_async_func_executed_with_wait_after_wait_time_but_it_was_it_should_throw()
Expand Down
26 changes: 26 additions & 0 deletions Tests/Shared.Specs/CollectionAssertionSpecs.cs
Expand Up @@ -197,6 +197,32 @@ public void When_collection_count_is_matched_against_a_predicate_and_collection_
"Expected collection to contain (c < 3) items because we want to test the behaviour with a null subject, but found <null>.");
}

[Fact]
public void When_collection_count_is_matched_against_a_predicate_it_should_not_throw()
{
// Arrange
IEnumerable collection = new[] { 1, 2, 3 };

// Act
Action act = () => collection.Should().HaveCount(c => c % 2 == 1);

// Assert
act.Should().NotThrow();
}

[Fact]
public void When_collection_count_is_matched_against_a_predicate_it_should_throw()
{
// Arrange
IEnumerable collection = new[] { 1, 2, 3 };

// Act
Action act = () => collection.Should().HaveCount(c => c % 2 == 0);

// Assert
act.Should().Throw<XunitException>();
}

[Fact]
public void When_counting_nongeneric_enumerable_it_should_enumerate()
{
Expand Down
21 changes: 21 additions & 0 deletions Tests/Shared.Specs/DateTimeOffsetValueFormatterSpecs.cs
Expand Up @@ -73,6 +73,27 @@ public void When_date_is_not_relevant_it_should_not_be_included_in_the_output()
result.Should().Be("<08:20:01>");
}

[InlineData("0001-01-02 04:05:06", "<0001-01-02 04:05:06>")]
[InlineData("0001-02-01 04:05:06", "<0001-02-01 04:05:06>")]
[InlineData("0002-01-01 04:05:06", "<0002-01-01 04:05:06>")]
[InlineData("0001-02-02 04:05:06", "<0001-02-02 04:05:06>")]
[InlineData("0002-01-02 04:05:06", "<0002-01-02 04:05:06>")]
[InlineData("0002-02-01 04:05:06", "<0002-02-01 04:05:06>")]
[InlineData("0002-02-02 04:05:06", "<0002-02-02 04:05:06>")]
[Theory]
public void When_date_is_relevant_it_should_be_included_in_the_output(string actual, string expected)
{
// Arrange
var formatter = new DateTimeOffsetValueFormatter();
var value = DateTime.Parse(actual, CultureInfo.InvariantCulture);

// Act
string result = formatter.Format(value, new FormattingContext(), null);

// Assert
result.Should().Be(expected);
}

[Fact]
public void When_a_full_date_and_time_is_specified_all_parts_should_be_included_in_the_output()
{
Expand Down
36 changes: 36 additions & 0 deletions Tests/Shared.Specs/GenericDictionaryAssertionSpecs.cs
Expand Up @@ -1525,6 +1525,24 @@ public void When_a_dictionary_contains_a_list_of_keys_it_should_throw_with_clear
"Expected dictionary {[1, One], [2, Two]} to not contain key {2, 3} because we do, but found {2}.");
}

[Fact]
public void When_a_dictionary_contains_exactly_one_of_the_keys_it_should_throw_with_clear_explanation()
{
// Arrange
var dictionary = new Dictionary<int, string>
{
[1] = "One",
[2] = "Two"
};

// Act
Action act = () => dictionary.Should().NotContainKeys(new[] { 2 }, "because {0}", "we do");

// Assert
act.Should().Throw<XunitException>().WithMessage(
"Expected dictionary {[1, One], [2, Two]} to not contain key 2 because we do.");
}

[Fact]
public void When_the_noncontents_of_a_dictionary_are_checked_against_an_empty_list_of_keys_it_should_throw_clear_explanation()
{
Expand Down Expand Up @@ -1763,6 +1781,24 @@ public void When_dictionary_does_not_contain_multiple_values_that_is_not_in_the_
act.Should().NotThrow<XunitException>();
}

[Fact]
public void When_a_dictionary_contains_a_exactly_one_of_the_values_it_should_throw_with_clear_explanation()
{
// Arrange
var dictionary = new Dictionary<int, string>
{
[1] = "One",
[2] = "Two"
};

// Act
Action act = () => dictionary.Should().NotContainValues(new[] { "Two" }, "because {0}", "we do");

// Assert
act.Should().Throw<XunitException>().WithMessage(
"Expected dictionary {[1, One], [2, Two]} to not contain value \"Two\" because we do.");
}

[Fact]
public void When_a_dictionary_contains_a_number_of_values_it_should_throw_with_clear_explanation()
{
Expand Down
26 changes: 26 additions & 0 deletions Tests/Shared.Specs/ReferenceTypeAssertionsSpecs.cs
Expand Up @@ -229,6 +229,32 @@ public void When_object_is_not_of_the_unexpected_open_generic_type_it_should_not
action.Should().NotThrow();
}

[Fact]
public void When_generic_object_is_not_of_the_unexpected_type_it_should_not_throw()
{
// Arrange
var aList = new System.Collections.Generic.List<string>();

// Act
Action action = () => aList.Should().NotBeOfType<string>();

// Assert
action.Should().NotThrow();
}

[Fact]
public void When_non_generic_object_is_not_of_the_unexpected_open_generic_type_it_should_not_throw()
{
// Arrange
var aString = "blah";

// Act
Action action = () => aString.Should().NotBeOfType(typeof(System.Collections.Generic.Dictionary<,>));

// Assert
action.Should().NotThrow();
}

[Fact]
public void When_asserting_object_is_not_of_type_and_it_is_null_it_should_throw()
{
Expand Down
71 changes: 71 additions & 0 deletions Tests/Shared.Specs/StringAssertionSpecs.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using FluentAssertions.Execution;
using Xunit;
using Xunit.Sdk;

Expand Down Expand Up @@ -458,6 +459,19 @@ public void When_a_string_does_match_the_equivalent_of_a_wildcard_pattern_it_sho
act.Should().NotThrow();
}

[Fact]
public void When_a_string_with_newline_matches_the_equivalent_of_a_wildcard_pattern_it_should_not_throw()
{
// Arrange
string subject = "hello\r\nworld!";

// Act
Action act = () => subject.Should().MatchEquivalentOf("helloworld!");

// Assert
act.Should().NotThrow();
}

#endregion

#region Not Match Equivalent Of
Expand Down Expand Up @@ -496,6 +510,19 @@ public void When_a_string_does_match_the_equivalent_of_a_pattern_but_it_shouldnt
#endif
}

[Fact]
public void When_a_string_with_newlines_does_match_the_equivalent_of_a_pattern_but_it_shouldnt_it_should_throw()
{
// Arrange
string subject = "hello\r\nworld!";

// Act
Action act = () => subject.Should().NotMatchEquivalentOf("helloworld!");

// Assert
act.Should().Throw<XunitException>();
}

#endregion

#region Match Regex
Expand Down Expand Up @@ -585,6 +612,28 @@ public void When_a_string_is_matched_against_an_invalid_regex_it_should_throw_wi
#endif
}

[Fact]
public void When_a_string_is_matched_against_an_invalid_regex_it_should_only_have_one_failure_message()
{
// Arrange
string subject = "hello world!";
string invalidRegex = ".**"; // Use local variable for this invalid regex to avoid static R# analysis errors

// Act
Action act = () =>
{
using (new AssertionScope())
{
subject.Should().MatchRegex(invalidRegex);
}
};

// Assert
act.Should().Throw<XunitException>()
.Which.Message.Should().Contain("is not a valid regular expression")
.And.NotContain("does not match");
}

#endregion

#region Not Match Regex
Expand Down Expand Up @@ -672,6 +721,28 @@ public void When_a_string_is_negatively_matched_against_an_invalid_regex_it_shou
#endif
}

[Fact]
public void When_a_string_is_negatively_matched_against_an_invalid_regex_it_only_contain_one_failure_message()
{
// Arrange
string subject = "hello world!";
string invalidRegex = ".**"; // Use local variable for this invalid regex to avoid static R# analysis errors

// Act
Action act = () =>
{
using (new AssertionScope())
{
subject.Should().NotMatchRegex(invalidRegex);
}
};

// Assert
act.Should().Throw<XunitException>()
.Which.Message.Should().Contain("is not a valid regular expression")
.And.NotContain("matches");
}

#endregion

#region Start With
Expand Down
34 changes: 34 additions & 0 deletions Tests/Shared.Specs/TypeAssertionSpecs.cs
Expand Up @@ -1428,6 +1428,40 @@ 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_a_selection_of_types_do_inherit_unexpected_attribute_with_the_expected_properties_it_succeeds()
{
// Arrange
var types = new TypeSelector(typeof(ClassWithInheritedAttribute));

// Act
Action act = () => types.Should()
.NotBeDecoratedWithOrInherit<DummyClassAttribute>(a => ((a.Name == "Expected") && a.IsEnabled),
"because we {0}", "do");

// Assert
act.Should().Throw<XunitException>()
.WithMessage("Expected all types to not be decorated with or inherit *DummyClassAttribute*" +
" that matches ((a.Name == \"Expected\")*a.IsEnabled) because we do," +
" but a matching attribute was found on the following types:*" +
"*ClassWithInheritedAttribute*.");
}

[Fact]
public void When_a_selection_of_types_do_not_inherit_unexpected_attribute_with_the_expected_properties_it_succeeds()
{
// Arrange
var types = new TypeSelector(typeof(ClassWithoutAttribute));

// Act
Action act = () => types.Should()
.NotBeDecoratedWithOrInherit<DummyClassAttribute>(a => ((a.Name == "Expected") && a.IsEnabled),
"because we {0}", "do");

// Assert
act.Should().NotThrow();
}

[Fact]
public void When_injecting_a_null_predicate_into_TypeSelector_NotBeDecoratedWithOrInherit_it_should_throw()
{
Expand Down