Skip to content

feat: migrate NSubstitute property Received gets and sets#51

Merged
vbreuss merged 3 commits into
mainfrom
topic/nsubstitute-11
May 1, 2026
Merged

feat: migrate NSubstitute property Received gets and sets#51
vbreuss merged 3 commits into
mainfrom
topic/nsubstitute-11

Conversation

@vbreuss
Copy link
Copy Markdown
Member

@vbreuss vbreuss commented May 1, 2026

This pull request extends the NSubstitute-to-Mockolate migration code fixer to support property verification conversions, in addition to existing method call verifications. It introduces logic to translate property "get" and "set" verifications (e.g., sub.Received().Prop and sub.Received().Prop = v) into the corresponding Mockolate verification chains, and adds comprehensive tests to ensure correct behavior.

Enhancements to property verification migration:

  • Added logic in NSubstituteCodeFixProvider.cs to identify and convert property verification expressions, such as property gets (_ = sub.Received().Prop) and sets (sub.Received().Prop = v), to Mockolate's .Mock.Verify.Prop.Got().AtLeastOnce() and .Mock.Verify.Prop.Set(v).AtLeastOnce() respectively. Negative cases like DidNotReceive are mapped to .Never().
  • Integrated the new property verification replacements into the main conversion flow, ensuring that these expressions are detected, replaced, and that the appropriate using Mockolate.Verify; directive is added when necessary.

Test coverage improvements:

  • Added new tests in NSubstituteCodeFixProviderTests.VerifyTests.cs to verify correct rewriting of property get and set verifications, including both positive (Received) and negative (DidNotReceive) cases.

@vbreuss vbreuss self-assigned this May 1, 2026
Copilot AI review requested due to automatic review settings May 1, 2026 11:59
@vbreuss vbreuss added the enhancement New feature or request label May 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

Test Results

  3 files  ± 0    3 suites  ±0   2m 20s ⏱️ -14s
126 tests + 4  126 ✅ + 4  0 💤 ±0  0 ❌ ±0 
378 runs  +12  378 ✅ +12  0 💤 ±0  0 ❌ ±0 

Results for commit fc3998c. ± Comparison against base commit ac5e77c.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds NSubstitute-to-Mockolate code fix support for property-style Received/DidNotReceive verifications (property gets/sets), along with new verification tests.

Changes:

  • Add code-fix rewrite for property-set verifications like sub.Received().Prop = value / sub.DidNotReceive().Prop = value.
  • Add code-fix rewrite for property-get verifications expressed as discard assignments like _ = sub.Received().Prop.
  • Extend NSubstitute code-fix tests to cover the new property get/set scenarios.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
Tests/Mockolate.Migration.Tests/NSubstituteCodeFixProviderTests.VerifyTests.cs Adds new tests asserting property get/set Received/DidNotReceive rewrites.
Source/Mockolate.Migration.Analyzers.CodeFixers/NSubstituteCodeFixProvider.cs Implements property get/set verification rewrite logic and ensures Mockolate.Verify using is added when needed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Tests/Mockolate.Migration.Tests/NSubstituteCodeFixProviderTests.VerifyTests.cs Outdated
Comment thread Tests/Mockolate.Migration.Tests/NSubstituteCodeFixProviderTests.VerifyTests.cs Outdated
Comment thread Source/Mockolate.Migration.Analyzers.CodeFixers/NSubstituteCodeFixProvider.cs Outdated
vbreuss and others added 2 commits May 1, 2026 14:08
…uple

Sonar S107 flagged the method's eight parameters. Returning a nullable
named tuple drops it to four and lets callers pattern-match the result.
The property-set verification migration emitted the RHS verbatim, so
sub.Received().Name = Arg.Any<string>() became
sub.Mock.Verify.Name.Set(Arg.Any<string>()).Never() — the NSubstitute
matcher was never translated. Now BuildPropertyVerifySetArgs runs the
shared Arg.* → It.* rewrite and wraps non-matcher values in It.Is(...),
matching the convention used by the Moq VerifySet migration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 1, 2026 12:29
@vbreuss vbreuss enabled auto-merge (squash) May 1, 2026 12:29
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 1, 2026

@vbreuss vbreuss merged commit 9cdbeca into main May 1, 2026
11 checks passed
@vbreuss vbreuss deleted the topic/nsubstitute-11 branch May 1, 2026 12:32
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

{
continue;
}

Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindAndBuildPropertyVerifyReplacements rewrites any matching SimpleAssignmentExpression regardless of where the assignment appears. Since assignment expressions can be used as sub-expressions (not just statements), this code fix could change semantics or produce non-compiling code when the assignment’s value is used. Consider restricting rewrites to assignments whose parent is an ExpressionStatementSyntax (and, for the get case, a discard assignment used as a statement) to ensure only verification-style usages are migrated.

Suggested change
if (assignment.Parent is not ExpressionStatementSyntax)
{
continue;
}

Copilot uses AI. Check for mistakes.
/// Translates property-style verifications:
/// <list type="bullet">
/// <item><c>_ = sub.Received().Prop</c> → <c>sub.Mock.Verify.Prop.Got().AtLeastOnce()</c></item>
/// <item><c>sub.Received().Prop = v</c> → <c>sub.Mock.Verify.Prop.Set(v).AtLeastOnce()</c></item>
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XML doc example for property sets shows sub.Mock.Verify.Prop.Set(v)..., but the implementation wraps non-matcher values in It.Is(...) (e.g., Set(It.Is("x"))). Consider updating the example/comment to reflect the actual output so the documentation matches behavior.

Suggested change
/// <item><c>sub.Received().Prop = v</c> → <c>sub.Mock.Verify.Prop.Set(v).AtLeastOnce()</c></item>
/// <item><c>sub.Received().Prop = "x"</c> → <c>sub.Mock.Verify.Prop.Set(It.Is("x")).AtLeastOnce()</c></item>

Copilot uses AI. Check for mistakes.
Comment on lines +648 to +652
if (expression is not MemberAccessExpressionSyntax propertyAccess ||
propertyAccess.Expression is not InvocationExpressionSyntax receivedInvocation ||
receivedInvocation.Expression is not MemberAccessExpressionSyntax receivedAccess)
{
return null;
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TryExtractReceivedPropertyAccess only checks the syntax shape sub.Received().X but doesn’t confirm that X resolves to an actual property. This can mis-rewrite cases like method-group accesses (e.g., _ = sub.Received().SomeMethod;) into Verify.SomeMethod.Got() which likely won’t compile. Consider using the semantic model to ensure propertyAccess (or propertyAccess.Name) binds to an IPropertySymbol before treating it as a property verification.

Copilot uses AI. Check for mistakes.
@github-actions github-actions Bot added the state: released The issue is released label May 1, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

This is addressed in release v0.5.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants