NSubstitute icon indicating copy to clipboard operation
NSubstitute copied to clipboard

Query doesn't catch all matching calls

Open firelizzard18 opened this issue 7 years ago • 10 comments

Shouldn't Query.cs line 14 read:

var allMatchingCallsOnTarget = target.ReceivedCalls().Where(callSpecification.CreateCopyThatMatchesAnyArguments().IsSatisfiedBy);

Rather than

var allMatchingCallsOnTarget = target.ReceivedCalls().Where(callSpecification.IsSatisfiedBy);

I'm trying to test a sequence. I have a bug, but I'm not getting the expected error. The actually received calls list omits WriteAttributeValue("value type-Decimal error type-unsupported"). I've used sub.When(...).Do((string s) => Console.WriteLine($"writing attribute value: {s}")), and I got the expected output (writing attribute value: value type-Decimal error type-unsupported), so I know it's being called, with those arguments.

Expected

Expected to receive these calls in order:

    WriteElementStart("span")
    WriteAttributeStart("class")
    WriteAttributeValue("value type-Decimal")
    WriteAttributeEnd()
    WriteElementText("133.3")
    WriteElementEnd(any Boolean)

Actually received matching calls in this order:

    WriteElementStart("span")
    WriteAttributeStart("class")
    WriteAttributeValue("value type-Decimal error type-unsupported")
    WriteAttributeEnd()
    WriteElementText("133.3")
    WriteElementEnd(False)

Actual

Expected to receive these calls in order:

    WriteElementStart("span")
    WriteAttributeStart("class")
    WriteAttributeValue("value type-Decimal")
    WriteAttributeEnd()
    WriteElementText("133.3")
    WriteElementEnd(any Boolean)

Actually received matching calls in this order:

    WriteElementStart("span")
    WriteAttributeStart("class")
    WriteAttributeEnd()
    WriteElementText("133.3")
    WriteElementEnd(False)

firelizzard18 avatar Feb 05 '18 08:02 firelizzard18

Thanks for reporting the issue. Unfortunately I can't quite understand the problem by the code you provided. Could you please post a small test case, so that I could reproduce the issue. Thank you!

alexandrnikitin avatar Feb 05 '18 12:02 alexandrnikitin

FYI StackOverflow calls that "Minimal, Complete, and Verifiable example" and has a great article about it.

zvirja avatar Feb 05 '18 12:02 zvirja

The problem is that Query.Add() (used by Received.InOrder(() => { ... })) doesn't seem to be capturing calls when the parameters don't match. I expect Received.InOrder to give me an error indicating that I called WriteAttributeValue in the correct order but with incorrect parameters. Instead, it does not capture the call to WriteAttributeValue at all, and completely omits it from the "Actually received matching calls".

I'll work on an example when I have time.

firelizzard18 avatar Feb 05 '18 17:02 firelizzard18

@firelizzard18 Any chance to follow up on this? 😟

zvirja avatar Jul 12 '18 20:07 zvirja

LINQPad Example (zip of file):

void Main()
{
    var sub = Substitute.For<I>();

    sub.When(x => x.A(Arg.Any<string>())).Do(x => $"A: {x.Arg<string>()}".Dump());
    sub.When(x => x.B(Arg.Any<string>())).Do(x => $"B: {x.Arg<string>()}".Dump());
    sub.When(x => x.C(Arg.Any<string>())).Do(x => $"C: {x.Arg<string>()}".Dump());

    sub.A("x");
    sub.B("w");
    sub.C("z");

    try
    {
        Received.InOrder(() =>
        {
            sub.A("x");
            sub.B("y");
            sub.C("z");
        });
    }
    catch (Exception ex)
    {
        ex.Message.Dump();
    }
}

public interface I
{
    void A(string s);
    void B(string s);
    void C(string s);
}

Dump() is an extension method provided by LINQPad but can be roughly approximated by:

public static T Dump<T>(this T obj) => Console.WriteLine(obj);

Expected output

A: x
B: w
C: z

Expected to receive these calls in order:

    A("x")
    B("y")
    C("z")

Actually received matching calls in this order:

    A("x")
    A("w")      <== THIS IS MISSING from the actual output
    C("z")

Actual output

A: x
B: w
C: z

Expected to receive these calls in order:

    A("x")
    B("y")
    C("z")

Actually received matching calls in this order:

    A("x")
    C("z")

firelizzard18 avatar Jul 13 '18 02:07 firelizzard18

FYI StackOverflow calls that "Minimal, Complete, and Verifiable example" and has a great article about it.

FYI, if most developers are anything like me, they will find this condescending. I may have cared more about responding if you had refrained from making that comment.

firelizzard18 avatar Jul 13 '18 02:07 firelizzard18

@firelizzard18

FYI, if most developers are anything like me, they will find this condescending. I may have cared more about responding if you had refrained from making that comment.

Thanks very much for this feedback! Sorry for the wording choice, we'll try to find better ways of asking for more information in future (maybe just "Please provide more information to help us reproduce this (SO has some helpful tips for providing example code). Thanks!" ?)

And thanks for coming back to leave an excellent repro example despite this. 👍

dtchepak avatar Jul 13 '18 02:07 dtchepak

I did not mind the request for an example/reproduction. The wording of the second comment seemed to imply that I was not already familiar with writing such examples.

I like your example ("Please provide more info..."). You could also reword the second comment as follows:

If you are unsure of how to write such an example, I suggest reading this StackOverflow article on writing a "minimal, complete, and verifiable example."

firelizzard18 avatar Jul 13 '18 03:07 firelizzard18

FYI StackOverflow calls that "Minimal, Complete, and Verifiable example" and has a great article about it.

FYI, if most developers are anything like me, they will find this condescending. I may have cared more about responding if you had refrained from making that comment.

@firelizzard18 Many thanks for sharing the feedback! Yesterday when I skimmed through the issue I also spotted this place and thought that it's easy to misinterpret it. The key point is that I targeted this comment to @alexandrnikitin rather than you. He wrote "Could you please post a small test case, so that I could reproduce the issue?" and I wanted Alex to know that he could reference the StackOverflow article for such kind of requests.

I missed to tag Alex, so it might look like I'm answering to you. And indeed, if it's read like this it sounds rude. I apologize for that and I'm graceful that you returned this back to me, so I have a chance to explain!

It's a good lesson that it's always better to tag people you are targeting the answer to.

P.S. Thanks for providing the clarified issue scenario, I'll take a look into it later (if it's not done by somebody else) 🙏

zvirja avatar Jul 13 '18 08:07 zvirja

Ah. I definitely did think you were responding to me. Thanks for the clarification :)

firelizzard18 avatar Jul 13 '18 17:07 firelizzard18