Skip to content

Commit 2bc4356

Browse files
authored
Merge pull request #2 from MrLuje/feature/nsubstitute
Feature/nsubstitute
2 parents 1aacb7a + 3b4b89f commit 2bc4356

File tree

12 files changed

+520
-396
lines changed

12 files changed

+520
-396
lines changed

.czrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "path": "cz-conventional-changelog" }

Mocking.Helpers/Mocking.Helpers.Vsix/Mocking.Helpers.Vsix.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
33
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4+
<Import Project="..\..\packages\Microsoft.VSSDK.BuildTools\build\Microsoft.VSSDK.BuildTools.props" Condition="Exists('..\..\packages\Microsoft.VSSDK.BuildTools\build\Microsoft.VSSDK.BuildTools.props')" Label="Paket" />
45
<PropertyGroup>
56
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
67
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
@@ -68,6 +69,7 @@
6869
<StartArguments>/rootsuffix Roslyn</StartArguments>
6970
</PropertyGroup>
7071
<ItemGroup>
72+
<None Include="paket.references" />
7173
<None Include="source.extension.vsixmanifest">
7274
<SubType>Designer</SubType>
7375
</None>
@@ -98,4 +100,5 @@
98100
</ItemGroup>
99101
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
100102
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
103+
<Import Project="..\..\packages\Microsoft.VSSDK.BuildTools\build\Microsoft.VSSDK.BuildTools.targets" Condition="Exists('..\..\packages\Microsoft.VSSDK.BuildTools\build\Microsoft.VSSDK.BuildTools.targets')" Label="Paket" />
101104
</Project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Microsoft.VSSDK.BuildTools

Mocking.Helpers/Mocking.Helpers/CompletionService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.CodeAnalysis.Completion;
33
using Microsoft.CodeAnalysis.CSharp;
44
using Microsoft.CodeAnalysis.CSharp.Syntax;
5+
using Mocking.Helpers.Interfaces;
56
using Mocking.Helpers.Moq;
67
using System;
78
using System.Linq;
@@ -15,9 +16,9 @@ public class CompletionService
1516
private CompletionItemRules _defaultCompletions;
1617
private readonly SyntaxToken _token;
1718
private readonly SemanticModel _semanticModel;
18-
private readonly MoqProvider _provider;
19+
private readonly BaseMockingProvider _provider;
1920

20-
public CompletionService(CompletionContext context, SyntaxToken token, SemanticModel semanticModel, MoqProvider provider)
21+
public CompletionService(CompletionContext context, SyntaxToken token, SemanticModel semanticModel, BaseMockingProvider provider)
2122
{
2223
_context = context;
2324
_token = token;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
8+
namespace Mocking.Helpers.Interfaces
9+
{
10+
public abstract class BaseMockingProvider
11+
{
12+
public abstract string AssemblyName { get; }
13+
public abstract string MockingMethodName { get; }
14+
public abstract string MockingWildcardMethod { get; }
15+
16+
protected string FormatMockingWildcardMethod(string parameterTypeName)
17+
{
18+
return string.Format(this.MockingWildcardMethod, parameterTypeName);
19+
}
20+
21+
public virtual string GenerateSuggestionForParameterWildcard(SemanticModel model, IMethodSymbol methodSymbol, ArgumentListSyntax arguments)
22+
{
23+
var suggestionParameter = methodSymbol.Parameters.Aggregate(String.Empty, (acc, p) => $"{acc}, {this.FormatMockingWildcardMethod(p.Type.ToMinimalDisplayString(model, arguments.SpanStart))}").TrimStart(',').Trim();
24+
return suggestionParameter;
25+
}
26+
27+
public virtual string GenerateSuggestionForParameterWildcardOfType(SemanticModel model, ITypeSymbol typeSymbol, ArgumentListSyntax arguments)
28+
{
29+
var suggestionParameter = this.FormatMockingWildcardMethod(typeSymbol.ToMinimalDisplayString(model, arguments.SpanStart));
30+
return suggestionParameter;
31+
}
32+
}
33+
}

Mocking.Helpers/Mocking.Helpers/Moq/MoqIsAnyCompletion.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
3636
var syntaxRoot = await context.Document.GetSyntaxRootAsync();
3737
var token = SyntaxHelpers.GetSelectedTokens(syntaxRoot, context.Position);
3838

39-
// ?ot in an opened method
39+
// Not in an opened method
4040
if (token.Parent == null) return;
4141

4242
var mockedMethodArgumentList = token.Parent as ArgumentListSyntax;
@@ -48,7 +48,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context)
4848
if (setupMethodInvocation == null) return;
4949

5050
var semanticModel = await context.Document.GetSemanticModelAsync();
51-
var matchingMockedMethods = SyntaxHelpers.GetCandidatesMockedMethodSignatures(semanticModel, setupMethodInvocation);
51+
var matchingMockedMethods = SyntaxHelpers.GetCandidatesMockedMethodSignaturesForLambda(semanticModel, setupMethodInvocation);
5252

5353
var completionService = new CompletionService(context, token, semanticModel, this._provider);
5454

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,17 @@
11
using Microsoft.CodeAnalysis;
22
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
using Mocking.Helpers.Interfaces;
34
using System;
45
using System.Collections.Generic;
56
using System.Linq;
67
using System.Text;
78

89
namespace Mocking.Helpers.Moq
910
{
10-
public class MoqProvider
11+
public class MoqProvider : BaseMockingProvider
1112
{
12-
public string MockingMethodName { get; } = "Setup";
13-
public string AssemblyName { get; } = "Moq";
14-
public string MockingWildcardMethod { get; } = "It.IsAny<{0}>()";
15-
16-
string FormatMockingWildcardMethod(string parameterTypeName)
17-
{
18-
return string.Format(this.MockingWildcardMethod, parameterTypeName);
19-
}
20-
21-
public string GenerateSuggestionForParameterWildcard(SemanticModel model, IMethodSymbol methodSymbol, ArgumentListSyntax arguments)
22-
{
23-
var suggestionParameter = methodSymbol.Parameters.Aggregate(String.Empty, (acc, p) => $"{acc}, {this.FormatMockingWildcardMethod(p.Type.ToMinimalDisplayString(model, arguments.SpanStart))}").TrimStart(',').Trim();
24-
return suggestionParameter;
25-
}
26-
27-
public string GenerateSuggestionForParameterWildcardOfType(SemanticModel model, ITypeSymbol typeSymbol, ArgumentListSyntax arguments)
28-
{
29-
var suggestionParameter = this.FormatMockingWildcardMethod(typeSymbol.ToMinimalDisplayString(model, arguments.SpanStart));
30-
return suggestionParameter;
31-
}
13+
public override string MockingMethodName => "Setup";
14+
public override string AssemblyName => "Moq";
15+
public override string MockingWildcardMethod => "It.IsAny<{0}>()";
3216
}
3317
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.Completion;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace Mocking.Helpers.NSubstitute
11+
{
12+
[ExportCompletionProvider(nameof(NSubstituteArgAnyCompletion), LanguageNames.CSharp)]
13+
public class NSubstituteArgAnyCompletion : CompletionProvider
14+
{
15+
private NSubstituteProvider _provider;
16+
17+
public NSubstituteArgAnyCompletion()
18+
{
19+
this._provider = new NSubstituteProvider();
20+
}
21+
22+
internal bool IsSubstituteForMethod(InvocationExpressionSyntax invocation)
23+
{
24+
return SyntaxHelpers.IsMethodNamed(invocation, this._provider.MockingMethodName);
25+
}
26+
27+
public override async Task ProvideCompletionsAsync(CompletionContext context)
28+
{
29+
try
30+
{
31+
if (!context.Document.SupportsSemanticModel || !context.Document.SupportsSyntaxTree) return;
32+
33+
var hasNSubstituteReferenced = context.Document.Project.MetadataReferences.Any(r => r.Display.Contains(this._provider.AssemblyName));
34+
if (!hasNSubstituteReferenced) return;
35+
36+
var syntaxRoot = await context.Document.GetSyntaxRootAsync();
37+
var token = SyntaxHelpers.GetSelectedTokens(syntaxRoot, context.Position);
38+
39+
// Not in an opened method
40+
if (token.Parent == null) return;
41+
42+
var mockedMethodArgumentList = token.Parent as ArgumentListSyntax;
43+
var mockedMethodInvocation = mockedMethodArgumentList.Ancestors()
44+
.OfType<InvocationExpressionSyntax>()
45+
.FirstOrDefault();
46+
47+
if (mockedMethodInvocation == null) return;
48+
49+
var semanticModel = await context.Document.GetSemanticModelAsync();
50+
var matchingMockedMethods = SyntaxHelpers.GetCandidatesMockedMethodSignatures(semanticModel, mockedMethodInvocation);
51+
52+
var completionService = new CompletionService(context, token, semanticModel, this._provider);
53+
54+
foreach (IMethodSymbol matchingMockedMethodSymbol in matchingMockedMethods)
55+
{
56+
completionService.AddSuggestionsForMethod(matchingMockedMethodSymbol, mockedMethodArgumentList);
57+
}
58+
}
59+
catch
60+
{
61+
}
62+
}
63+
}
64+
}
65+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp.Syntax;
3+
using Mocking.Helpers.Interfaces;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Text;
7+
8+
namespace Mocking.Helpers.NSubstitute
9+
{
10+
public class NSubstituteProvider : BaseMockingProvider
11+
{
12+
public override string AssemblyName => "NSubstitute";
13+
public override string MockingMethodName => "For";
14+
public override string MockingWildcardMethod => "Arg.Any<{0}>()";
15+
}
16+
}

Mocking.Helpers/Mocking.Helpers/SyntaxHelpers.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,27 @@ static internal SyntaxToken GetSelectedTokens(SyntaxNode node, int currentPositi
4040
}
4141

4242
/// <summary>
43-
/// Get all signature candidates which have parameters
43+
/// Get all signature candidates which have parameters in a lambda call
4444
/// </summary>
4545
/// <param name="semanticModel"></param>
4646
/// <param name="setupMethodInvocation"></param>
4747
/// <returns></returns>
48-
static internal IEnumerable<IMethodSymbol> GetCandidatesMockedMethodSignatures(SemanticModel semanticModel, InvocationExpressionSyntax setupMethodInvocation)
48+
static internal IEnumerable<IMethodSymbol> GetCandidatesMockedMethodSignaturesForLambda(SemanticModel semanticModel, InvocationExpressionSyntax setupMethodInvocation)
4949
{
5050
var setupLambda = setupMethodInvocation.ArgumentList.Arguments.FirstOrDefault()?.Expression as LambdaExpressionSyntax;
5151

5252
var methodToMockInLambda = setupLambda?.Body as InvocationExpressionSyntax;
53+
return GetCandidatesMockedMethodSignatures(semanticModel, methodToMockInLambda);
54+
}
55+
56+
/// <summary>
57+
/// Get all signature candidates which have parameters in a lambda call
58+
/// </summary>
59+
/// <param name="semanticModel"></param>
60+
/// <param name="methodToMockInLambda"></param>
61+
/// <returns></returns>
62+
static internal IEnumerable<IMethodSymbol> GetCandidatesMockedMethodSignatures(SemanticModel semanticModel, InvocationExpressionSyntax methodToMockInLambda)
63+
{
5364
if (methodToMockInLambda == null) return Enumerable.Empty<IMethodSymbol>();
5465

5566
var mockSignatures = new List<IMethodSymbol>();

0 commit comments

Comments
 (0)