shouldly / shouldly

Should testing for .NET—the way assertions should be!

Home Page:https://docs.shouldly.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Collection message formatter throws on null collection

Crozin opened this issue · comments

Having two collections where one of them is null Shouldly can't produce proper assertion message:

string[] actual = null;
string[] expected = new[] { "hello", "world" };

actual.ShouldBe(expected, true);

Throws:

System.ArgumentNullException: Value cannot be null. (Parameter 'source')
   at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)
   at System.Linq.Enumerable.Cast[TResult](IEnumerable source)
   at Shouldly.MessageGenerators.ShouldBeIgnoringOrderMessageGenerator.GenerateErrorMessage(IShouldlyAssertionContext context)
   at Shouldly.ShouldlyMessage.GenerateShouldMessage()
   at Shouldly.ShouldlyMessage.ToString()
   at Shouldly.ShouldlyCoreExtensions.AssertAwesomelyIgnoringOrder[T](T actual, Func`2 specifiedConstraint, Object originalActual, Object originalExpected, Func`1 customMessage, String shouldlyMethod)
   at Shouldly.ShouldBeTestExtensions.ShouldBe[T](IEnumerable`1 actual, IEnumerable`1 expected, Boolean ignoreOrder, Func`1 customMessage)
   at Shouldly.ShouldBeTestExtensions.ShouldBe[T](IEnumerable`1 actual, IEnumerable`1 expected, Boolean ignoreOrder)
   at ...

Looks like ShouldBeIgnoringOrderMessageGenerator misses support for null support in context.Actual and context.Expected.

Most specialized ShouldBe overloads do not support null arguments by design. For example, null tasks, null strings, etc. We could reconsider this and it would require some design work to make sure we get it right, since it's a new layer of complexity.

However, in the current state of things as it has been from the beginning where we treat it as an API error to call a collection assertion with a null collection, we should be throwing ArgumentNullException directly in the ShouldBe method that is called and not allowing it to propagate down to an internal spot like this which makes it look like an accident. I propose fixing this first.

In the meantime, if you want to compose both a non-null check and a specialized check like a collection assertion, you can do this:

actual.ShouldNotBeNull().ShouldBe(expected, true);

Most specialized ShouldBe overloads do not support null arguments by design.

I find that a bit counterintuitive.

string[] myColl = new[] { "a", "b" } ;
myColl.ShouldBe(null); // works fine, reports invalid value
myColl.ShouldBe(new[] { "b", "a" }); // works fine, reports invalid value
myColl.ShouldBe(new[] { "b", "a" }, true); // works fine, continues as test match

string[] myColl = null;
myColl.ShouldBe(null); // works fine, continues as test match
myColl.ShouldBe(new[] { "b", "a" }); // works fine, reports invalid value
myColl.ShouldBe(new[] { "b", "a" }, true); // throws null-related exception

@jnm2 Sir, I am a first-time contributor and have been working on this issue since last week for my knowledge, i have been in never in open source which I want to now start. can I take this issue? Thank you, Gaurang