LambdaCompare icon indicating copy to clipboard operation
LambdaCompare copied to clipboard

Possible type coercion issue

Open mostlybob opened this issue 3 years ago • 4 comments

I'm seeing a possible issue with type coercion using LambdaCompare in a unit test. I have a condition where I'm comparing a long value to an int value. I have a unit test that seems like it should pass, but it doesn't. To test this, I changed the property that is currently an int to a long and reran the test successfully. For design reasons made prior to my involvement with the project, I'm not currently in a position to make that change, as it would impact other parts of the system.

Both the unit test code and the code in the system under test is in VS 2019 with .NET Framework 4.8.

I'm using Neleus.LambdaCompare version 1.0.3, installed via Nuget.

I put together some sample code that should demonstrate what I'm seeing.

public class UseLongId
{
  public long ID { get; set;}
  public Guid EntityID { get; set; }
}

public class UseIntId
{
  public int ID { get; set;}
}


#region  -------------  in the system under test

var usesIntId = new UseIntId {ID = 665544};  // arbitrarily set ID = 665544 for demo to be consistent with unit test code

List<Guid> usesLongIds = db
    .Query<UseLongId>(x => x.ID == usesIntId.DealerID || x.DealerID == 0)
    .Select(x => x.EntityID)
    .Distinct()
    .ToList();
#endregion

#region  -------------  in the unit test
// using NSubstitute in a unit test - use of Arg.Is<>() comes from NSubstitute

int DealerId =665544;

someNSubstituteDatabaseMock
    .Received()
    .Query(Arg.Is<Expression<Func<UseLongId, bool>>>(x =>
       Neleus.LambdaCompare.Lambda.Eq(x, y => y.DealerID == DealerId || y.DealerID == 0)));
#endregion

Here's the error output from the failed test:

NSubstitute.Exceptions.ReceivedCallsException : Expected to receive a call matching:
Query<UseLongId>(x => Eq(x, y => ((y.ID == 665544) OrElse (y.ID == 0))))
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
Query<UseLongId>(*x => ((x.ID == Convert(value(SomeArbitraryNamespace.DemoClass+<>c__DisplayClass8_0).usesIntId.ID)) OrElse (x.ID == 0))*)


Stack Trace:
ReceivedCallsExceptionThrower.Throw(ICallSpecification callSpecification, IEnumerable`1 matchingCalls, IEnumerable`1 nonMatchingCalls, Quantity requiredQuantity)
CheckReceivedCallsHandler.Handle(ICall call)
Route.Handle(ICall call)
CallRouter.Route(ICall call)
CastleForwardingInterceptor.Intercept(IInvocation invocation)
AbstractInvocation.Proceed()
ProxyIdInterceptor.Intercept(IInvocation invocation)
AbstractInvocation.Proceed()
ObjectProxy_1.Query[T](Expression`1 predicate)
GetExportParametersTests.It_should_demo_the_issue() line 229

mostlybob avatar Mar 30 '22 15:03 mostlybob

Please create a unit test in the project Neleus.LambdaCompare.Tests so I can review it easily. Thanks.

nullptre avatar Apr 01 '22 10:04 nullptre

I am continuing to look at this. Simple unit tests on Lambda.Eq don't appear to show the issue I'm observing. I have other frameworks involved in my own test where I'm seeing the issue, particularly NSubstitute The error I have in my original post suggests some involvement with System.Linq.Expressions in the Convert method. I'm brushing off some dusty knowledge about deconstructing expressions. :)

fwiw, I put together a couple of rather elementary tests to verify some assumptions. I don't think they'll be of much use here, but I thought I'd put them here to "show my work" a little bit:

const int intId = 665544;
const long longId = 665544;

[TestMethod]
public void VerifyLongToIntCoercion()
{
    Assert.AreEqual(intId, longId);
    Assert.AreEqual(longId, intId);
}

[TestMethod]
public void LambdaEqIntToLongCoercion()
{
  var entityId = Guid.NewGuid();
  var f1 = (Expression<Func<long, UseLongId>>)(z => new UseLongId
  {
      ID = longId,
      EntityID = entityId
  });
  var f2 = (Expression<Func<long, UseLongId>>)(z => new UseLongId
  {
      ID = intId,
      EntityID = entityId
  });

  Assert.IsTrue(Lambda.Eq(f1, f2));
}

mostlybob avatar Apr 18 '22 17:04 mostlybob

Hey @mostlybob, I've paused the issue for a long time, is it still actual?

nullptre avatar Mar 09 '23 19:03 nullptre

Hey @mostlybob, I've paused the issue for a long time, is it still actual?

I apologize, I should have followed up on this. I attempted to put tess together to exercise this issue but I was unable to create a test setup that matched the condition I saw. There were other frameworks involved, so it's possible that any actual issue could lie elsewhere.

I'm okay with closing this issue. If it becomes problematic for me, I'll attempt to isolate it better and bring it back up with tests and a pull request.

mostlybob avatar Mar 09 '23 23:03 mostlybob