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

Conflicting out/ref argument set #62

Closed
dtchepak opened this issue Dec 29, 2018 · 0 comments
Closed

Conflicting out/ref argument set #62

dtchepak opened this issue Dec 29, 2018 · 0 comments
Labels
enhancement New feature or request
Milestone

Comments

@dtchepak
Copy link
Member

It is possible to set argument values from .Returns and .AndDoes. At present the one set in .Returns wins (not sure we should always rely on this for future versions), but this can result in confusing results.

        public interface ILookup { bool Lookup(string key, out int i); }

        [Fact]
        public void Test() {
            var sub = Substitute.For<ILookup>();

            sub.Lookup("blah", out Arg.Any<int>())
               .Returns(x => {
                   x[1] = 42;
                   return true;
                })
               .AndDoes(x => x[1] = 45);

            sub.Lookup("blah", out var value);

            Assert.Equal(42, value); // The final values is 42 from the Returns, not 45 from AndDoes
        }

Draft documentation:

NS3006

CheckId NS3006
Category Argument specification

Cause

Conflicting assignments to out/ref arguments.

Rule description

A violation of this rule occurs when an out or ref argument is assigned via CallInfo in both a Returns and an AndDoes call.

How to fix violations

To fix a violation of this rule remove one of the assignments, so the argument is only assigned in either the Returns or the AndDoes block (not in both).

// Incorrect, argument assigned in `Returns` and `AndDoes`:
dictionary.TryGetValue("sample", out Arg.Any<int>())
   .Returns(x => {
       x[1] = 42;
       return true;
    })
   .AndDoes(x => x[1] = 45);

// Correct, only assigned in `AndDoes`:
dictionary.TryGetValue("sample", out Arg.Any<int>())
   .Returns(true)
   .AndDoes(x => x[1] = 45);

// Correct, only assign in `Returns`:
dictionary.TryGetValue("sample", out Arg.Any<int>())
   .Returns(x => {
       x[1] = 42;
       return true;
    });

How to suppress violations

This warning can be suppressed by disabling the warning in the ruleset file for the project.
The warning can also be suppressed programmatically for an assembly:

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Argument specification", "NS3006:Conflicting argument assignments.", Justification = "Reviewed")]

Or for a specific code block:

#pragma warning disable NS3006 // Conflicting argument assignments.
// the code which produces warning
#pragma warning disable NS3006 // Conflicting argument assignments.
@dtchepak dtchepak added the enhancement New feature or request label Dec 29, 2018
tpodolak added a commit that referenced this issue Mar 11, 2019
tpodolak added a commit that referenced this issue Mar 17, 2019
tpodolak added a commit that referenced this issue Mar 17, 2019
@tpodolak tpodolak added this to the 1.0.8 milestone Mar 17, 2019
@tpodolak tpodolak added this to the 1.0.8 milestone Apr 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants