Skip to content

Commit d568c62

Browse files
authored
Add Moq onboarding analyzer and constructor guidance (#83)
* Add Moq onboarding analyzer and constructor guidance * Fix analyzer review findings * Fix WaitFor timeout behavior and document change
1 parent 3148ca7 commit d568c62

22 files changed

Lines changed: 1346 additions & 101 deletions

FastMoq.Analyzers.Tests/AnalyzerTestHelpers.cs

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ internal static class AnalyzerTestHelpers
1818
{
1919
public static async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(string source, params DiagnosticAnalyzer[] analyzers)
2020
{
21-
return await GetDiagnosticsAsync(source, includeAzureFunctionsHelpers: false, analyzers).ConfigureAwait(false);
21+
return await GetDiagnosticsAsync(source, includeAzureFunctionsHelpers: false, includeMoqProviderPackage: true, includeNSubstituteProviderPackage: true, analyzers).ConfigureAwait(false);
2222
}
2323

2424
public static async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(string source, bool includeAzureFunctionsHelpers, params DiagnosticAnalyzer[] analyzers)
2525
{
26-
var document = CreateDocument(source, includeAzureFunctionsHelpers);
26+
return await GetDiagnosticsAsync(source, includeAzureFunctionsHelpers, includeMoqProviderPackage: true, includeNSubstituteProviderPackage: true, analyzers).ConfigureAwait(false);
27+
}
28+
29+
public static async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(string source, bool includeAzureFunctionsHelpers, bool includeMoqProviderPackage, bool includeNSubstituteProviderPackage, params DiagnosticAnalyzer[] analyzers)
30+
{
31+
var document = CreateDocument(source, includeAzureFunctionsHelpers, includeMoqProviderPackage, includeNSubstituteProviderPackage);
2732
return await GetDiagnosticsAsync(document, analyzers).ConfigureAwait(false);
2833
}
2934

@@ -41,9 +46,14 @@ public static async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(Documen
4146
.ConfigureAwait(false);
4247
}
4348

44-
public static async Task<string> ApplyCodeFixAsync(string source, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string diagnosticId, bool includeAzureFunctionsHelpers = false, int diagnosticOccurrence = 0, string? diagnosticMessageContains = null)
49+
public static async Task<string> ApplyCodeFixAsync(string source, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string diagnosticId, bool includeAzureFunctionsHelpers = false, int diagnosticOccurrence = 0, string? diagnosticMessageContains = null, string? codeFixTitle = null)
50+
{
51+
return await ApplyCodeFixAsync(source, analyzer, codeFixProvider, diagnosticId, includeAzureFunctionsHelpers, includeMoqProviderPackage: true, includeNSubstituteProviderPackage: true, diagnosticOccurrence, diagnosticMessageContains, codeFixTitle).ConfigureAwait(false);
52+
}
53+
54+
public static async Task<string> ApplyCodeFixAsync(string source, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string diagnosticId, bool includeAzureFunctionsHelpers, bool includeMoqProviderPackage, bool includeNSubstituteProviderPackage, int diagnosticOccurrence = 0, string? diagnosticMessageContains = null, string? codeFixTitle = null)
4555
{
46-
var document = CreateDocument(source, includeAzureFunctionsHelpers);
56+
var document = CreateDocument(source, includeAzureFunctionsHelpers, includeMoqProviderPackage, includeNSubstituteProviderPackage);
4757
var diagnostics = await GetDiagnosticsAsync(document, analyzer).ConfigureAwait(false);
4858
var diagnostic = diagnostics
4959
.Where(item => item.Id == diagnosticId)
@@ -55,7 +65,9 @@ public static async Task<string> ApplyCodeFixAsync(string source, DiagnosticAnal
5565
var context = new CodeFixContext(document, diagnostic, (action, _) => actions.Add(action), CancellationToken.None);
5666
await codeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
5767

58-
var action = actions.Single();
68+
var action = codeFixTitle is null
69+
? actions.Single()
70+
: actions.Single(item => string.Equals(item.Title, codeFixTitle, StringComparison.Ordinal));
5971
var operations = await action.GetOperationsAsync(CancellationToken.None).ConfigureAwait(false);
6072
var changedSolution = operations.OfType<ApplyChangesOperation>().Single().ChangedSolution;
6173
var changedDocument = changedSolution.GetDocument(document.Id)!;
@@ -65,7 +77,12 @@ public static async Task<string> ApplyCodeFixAsync(string source, DiagnosticAnal
6577

6678
public static async Task<ImmutableArray<string>> GetCodeFixTitlesAsync(string source, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string diagnosticId, bool includeAzureFunctionsHelpers = false, int diagnosticOccurrence = 0, string? diagnosticMessageContains = null)
6779
{
68-
var document = CreateDocument(source, includeAzureFunctionsHelpers);
80+
return await GetCodeFixTitlesAsync(source, analyzer, codeFixProvider, diagnosticId, includeAzureFunctionsHelpers, includeMoqProviderPackage: true, includeNSubstituteProviderPackage: true, diagnosticOccurrence, diagnosticMessageContains).ConfigureAwait(false);
81+
}
82+
83+
public static async Task<ImmutableArray<string>> GetCodeFixTitlesAsync(string source, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string diagnosticId, bool includeAzureFunctionsHelpers, bool includeMoqProviderPackage, bool includeNSubstituteProviderPackage, int diagnosticOccurrence = 0, string? diagnosticMessageContains = null)
84+
{
85+
var document = CreateDocument(source, includeAzureFunctionsHelpers, includeMoqProviderPackage, includeNSubstituteProviderPackage);
6986
var diagnostics = await GetDiagnosticsAsync(document, analyzer).ConfigureAwait(false);
7087
var diagnostic = diagnostics
7188
.Where(item => item.Id == diagnosticId)
@@ -88,7 +105,7 @@ public static string NormalizeCode(string source)
88105
.ToFullString();
89106
}
90107

91-
private static Document CreateDocument(string source, bool includeAzureFunctionsHelpers = false)
108+
private static Document CreateDocument(string source, bool includeAzureFunctionsHelpers = false, bool includeMoqProviderPackage = true, bool includeNSubstituteProviderPackage = true)
92109
{
93110
var workspace = new AdhocWorkspace();
94111
var projectId = ProjectId.CreateNewId();
@@ -99,7 +116,7 @@ private static Document CreateDocument(string source, bool includeAzureFunctions
99116
.WithProjectParseOptions(projectId, new CSharpParseOptions(LanguageVersion.Preview))
100117
.WithProjectCompilationOptions(projectId, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
101118

102-
foreach (var metadataReference in GetMetadataReferences(includeAzureFunctionsHelpers))
119+
foreach (var metadataReference in GetMetadataReferences(includeAzureFunctionsHelpers, includeMoqProviderPackage, includeNSubstituteProviderPackage))
103120
{
104121
solution = solution.AddMetadataReference(projectId, metadataReference);
105122
}
@@ -108,7 +125,7 @@ private static Document CreateDocument(string source, bool includeAzureFunctions
108125
return solution.GetDocument(documentId)!;
109126
}
110127

111-
private static IEnumerable<MetadataReference> GetMetadataReferences(bool includeAzureFunctionsHelpers)
128+
private static IEnumerable<MetadataReference> GetMetadataReferences(bool includeAzureFunctionsHelpers, bool includeMoqProviderPackage, bool includeNSubstituteProviderPackage)
112129
{
113130
var references = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
114131
if (AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") is string trustedPlatformAssemblies)
@@ -121,13 +138,34 @@ private static IEnumerable<MetadataReference> GetMetadataReferences(bool include
121138
continue;
122139
}
123140

141+
if (!includeMoqProviderPackage &&
142+
string.Equals(Path.GetFileNameWithoutExtension(assemblyPath), "FastMoq.Provider.Moq", StringComparison.OrdinalIgnoreCase))
143+
{
144+
continue;
145+
}
146+
147+
if (!includeNSubstituteProviderPackage &&
148+
string.Equals(Path.GetFileNameWithoutExtension(assemblyPath), "FastMoq.Provider.NSubstitute", StringComparison.OrdinalIgnoreCase))
149+
{
150+
continue;
151+
}
152+
124153
references.Add(assemblyPath);
125154
}
126155
}
127156

128157
references.Add(typeof(FastMoq.Mocker).Assembly.Location);
129-
references.Add(typeof(FastMoq.Providers.MoqProvider.IFastMockMoqExtensions).Assembly.Location);
130-
references.Add(typeof(FastMoq.Providers.NSubstituteProvider.IFastMockNSubstituteExtensions).Assembly.Location);
158+
159+
if (includeMoqProviderPackage)
160+
{
161+
references.Add(typeof(FastMoq.Providers.MoqProvider.IFastMockMoqExtensions).Assembly.Location);
162+
}
163+
164+
if (includeNSubstituteProviderPackage)
165+
{
166+
references.Add(typeof(FastMoq.Providers.NSubstituteProvider.IFastMockNSubstituteExtensions).Assembly.Location);
167+
}
168+
131169
references.Add(typeof(Moq.Mock).Assembly.Location);
132170
references.Add(typeof(NSubstitute.Substitute).Assembly.Location);
133171
references.Add(typeof(Microsoft.Extensions.Logging.ILogger).Assembly.Location);

0 commit comments

Comments
 (0)