feat: migrate Moq properties#21
Conversation
There was a problem hiding this comment.
Pull request overview
Adds migration support for Moq property setups in the Moq→Mockolate code fix provider, with accompanying tests and updated example snippets.
Changes:
- Extend
MoqCodeFixProviderto rewriteSetup(x => x.Prop)andSetupProperty(...)into Mockolate’s property setup APIs. - Add new code-fix tests covering direct and nested property setups, plus
SetupPropertywith/without default values. - Update migration example file to demonstrate property setup migrations and recursive-mock property patterns.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| Tests/Mockolate.Migration.Tests/MoqCodeFixProviderTests.SetupTests.cs | Adds new test cases validating property setup and SetupProperty migrations. |
| Tests/Mockolate.Migration.Example.Tests/MoqMigrationExamples.cs | Extends example outputs/inputs to include property-related migration examples. |
| Source/Mockolate.Migration.Analyzers.CodeFixers/MoqCodeFixProvider.cs | Implements syntax rewrites for property Setup(...) and SetupProperty(...) patterns. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
13144b6 to
3721ba4
Compare
3721ba4 to
1e02ee1
Compare
# Conflicts: # Source/Mockolate.Migration.Analyzers.CodeFixers/MoqCodeFixProvider.cs # Tests/Mockolate.Migration.Example.Tests/MoqMigrationExamples.cs # Tests/Mockolate.Migration.Tests/MoqCodeFixProviderTests.NewMockTests.cs
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
Source/Mockolate.Migration.Analyzers.CodeFixers/MoqCodeFixProvider.cs:207
IsMockBehaviorArgumentrelies onsymbol?.ContainingType?.ToDisplayString() == "Moq.MockBehavior".ToDisplayString()defaults to a minimally-qualified format, which often returns justMockBehavior(no namespace), so this check can silently fail and prevent the code fix from running fornew Mock<T>(MockBehavior.*).
Consider using a symbol-based comparison instead (e.g., compare ContainingNamespace+Name, or compare against semanticModel.Compilation.GetTypeByMetadataName("Moq.MockBehavior"), or use the existing GloballyQualifiedNonGeneric() helper from TypeExtensions).
_ => null,
};
private static bool IsMockBehaviorArgument(ArgumentSyntax argument, SemanticModel? semanticModel, CancellationToken cancellationToken)
{
if (semanticModel is not null)
{
Source/Mockolate.Migration.Analyzers.CodeFixers/MoqCodeFixProvider.cs:230
HasStrictMockBehaviorcheckssymbol?.ToDisplayString() == "Moq.MockBehavior.Strict". As with otherToDisplayString()comparisons, this is likely to produce a minimally-qualified string (e.g.,MockBehavior.Strict), causing strict behavior to be missed and the migratedCreateMock(...)call to omitThrowingWhenNotSetup().
Use a more robust symbol identity check (namespace + containing type + member name), or compare via GetTypeByMetadataName("Moq.MockBehavior") and then validate the enum member name is Strict.
or "MockBehavior.Default" or "Moq.MockBehavior.Default";
}
private static bool HasStrictMockBehavior(ExpressionSyntax expressionSyntax, SemanticModel? semanticModel, CancellationToken cancellationToken)
{
if (expressionSyntax is not ObjectCreationExpressionSyntax { ArgumentList.Arguments: { Count: 1, } arguments, })
{
return false;
}
if (semanticModel is not null)
{
ISymbol? symbol = semanticModel.GetSymbolInfo(arguments[0].Expression, cancellationToken).Symbol;
return symbol?.ToDisplayString() == "Moq.MockBehavior.Strict";
}
Source/Mockolate.Migration.Analyzers.CodeFixers/MoqCodeFixProvider.cs:199
GetTypeArgument(andHasStrictMockBehavior) don’t handle target-typednew(...)with aMockBehaviorargument (i.e.,ImplicitObjectCreationExpressionSyntaxwith 1 argument). Since the analyzer reports onOperationKind.ObjectCreationfor MoqMock, this meansMock<IFoo> m = new(MockBehavior.Strict);would not be fixable even though it’s a common Moq pattern.
Add a case for ImplicitObjectCreationExpressionSyntax with 1 argument where the argument is a MockBehavior, and plumb that through to strict/loose handling as appropriate.
return document.WithSyntaxRoot(compilationUnit);
}
private static TypeSyntax? GetTypeArgument(ExpressionSyntax expressionSyntax, SemanticModel? semanticModel, CancellationToken cancellationToken) =>
expressionSyntax switch
{
ObjectCreationExpressionSyntax
{
Type: GenericNameSyntax { TypeArgumentList.Arguments: { Count: 1, } args, },
ArgumentList.Arguments.Count: 0,
Initializer: null,
}
=> args[0],
ObjectCreationExpressionSyntax
{
Type: GenericNameSyntax { TypeArgumentList.Arguments: { Count: 1, } args, },
ArgumentList: { Arguments: { Count: 1, } arguments, },
Initializer: null,
} when IsMockBehaviorArgument(arguments[0], semanticModel, cancellationToken)
=> args[0],
ImplicitObjectCreationExpressionSyntax { ArgumentList.Arguments.Count: 0, Initializer: null, }
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This is addressed in release v0.2.0. |



Adds migration support for Moq property setups in the Moq→Mockolate code fix provider, with accompanying tests and updated example snippets.
Changes:
MoqCodeFixProviderto rewriteSetup(x => x.Prop)andSetupProperty(...)into Mockolate’s property setup APIs.SetupPropertywith/without default values.