Skip to content

Chaining multiple collection asserts with index #4423

Description

@azygis

I'm not sure whether it's a bug or not, but consider the following code:

[Test]
public void Dummy()
{
    var items = new SomeStuff[]
    {
        new("Name 1"),
        new("Name 2")
    };

    // OK
    Assert.That(items, Has.Exactly(2).Items);
    Assert.That(items, Has.ItemAt(0).Property(nameof(SomeStuff.Name)).EqualTo("Name 1"));
    Assert.That(items, Has.ItemAt(1).Property(nameof(SomeStuff.Name)).EqualTo("Name 2"));

    // OK
    Assert.That(items, Has.Exactly(2).Items
        .And.One.Property(nameof(SomeStuff.Name)).EqualTo("Name 1")
        .And.One.Property(nameof(SomeStuff.Name)).EqualTo("Name 2"));

    // NOT OK 1
    Assert.That(items, Has.Exactly(2).Items
        .And.ItemAt(0).Property(nameof(SomeStuff.Name)).EqualTo("Name 1")
        .And.ItemAt(1).Property(nameof(SomeStuff.Name)).EqualTo("Name 2"));

    // NOT OK 2
    Assert.That(items, Has.Exactly(2).Items
        .And.One.ItemAt(0).Property(nameof(SomeStuff.Name)).EqualTo("Name 1")
        .And.One.ItemAt(1).Property(nameof(SomeStuff.Name)).EqualTo("Name 2"));
}

public sealed record SomeStuff(string Name);

How would one chain AndConstraint and use the indexer in the same Assert.That call? The NOT OK 1 assert throws:

System.InvalidOperationException : Stack empty.
   at System.Collections.Generic.Stack`1.ThrowForEmptyStack()
   at System.Collections.Generic.Stack`1.Pop()
   at NUnit.Framework.Constraints.ConstraintBuilder.ConstraintStack.Pop()
   at NUnit.Framework.Constraints.BinaryOperator.Reduce(ConstraintStack stack)
   at NUnit.Framework.Constraints.ConstraintBuilder.Resolve()
   at NUnit.Framework.Constraints.Constraint.NUnit.Framework.Constraints.IResolveConstraint.Resolve()
   at NUnit.Framework.Assert.That[TActual](TActual actual, IResolveConstraint expression, String message, Object[] args)
   at NUnit.Framework.Assert.That[TActual](TActual actual, IResolveConstraint expression)
   at SomeTests.Dummy() in /path/TestFile.cs:line 115
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

The NOT OK 2 assert throws:

System.ArgumentException : Default indexer accepting arguments < 0 > was not found on SomeTests+SomeStuff.
   at NUnit.Framework.Constraints.IndexerConstraint.ApplyTo[TActual](TActual actual)
   at NUnit.Framework.Constraints.ExactCountConstraint.ApplyTo[TActual](TActual actual)
   at NUnit.Framework.Constraints.AndConstraint.ApplyTo[TActual](TActual actual)
   at NUnit.Framework.Constraints.AndConstraint.ApplyTo[TActual](TActual actual)
   at NUnit.Framework.Assert.That[TActual](TActual actual, IResolveConstraint expression, String message, Object[] args)
   at NUnit.Framework.Assert.That[TActual](TActual actual, IResolveConstraint expression)
   at SomeTests.Dummy() in /path/TestFile.cs:line 115
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

Namespaces, file paths and test names have been changed to protect the innocent.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions