-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Add new rules: - PosInfoMoq2007: The `As<T>()` method can be used only with interfaces (fixes: #19). - PosInfoMoq2008: The `Verify()` method must be used only on overridable members. - Add the support of static methods `VerifyAll()` and `Verify()` for the PosInfoMoq2000 rule (fixes: #20). - Various optimizations to increase speed of analysis. - Various optimizations to reduce memory usage. - Add hyperlink to the documentation of the rules.
- Loading branch information
1 parent
f19dd54
commit da2f494
Showing
29 changed files
with
1,007 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# PosInfoMoq2007: The `As<T>()` method can be used only with interfaces. | ||
|
||
| Property | Value | | ||
|-------------------------------------|-----------------------------------------------------------------| | ||
| **Rule ID** | PosInfoMoq2007 | | ||
| **Title** | The `As<T>()` method can be used only with interfaces. | | ||
| **Category** | Compilation | | ||
| **Default severity** | Error | | ||
|
||
## Cause | ||
|
||
The `As<T>()` method is used with a type which is not an interface. | ||
|
||
## Rule description | ||
|
||
Moq allows to add additional implementations for mocked class (or interface) by adding additional interfaces | ||
with the `As<T>()` method. | ||
|
||
```csharp | ||
[Fact] | ||
public void Test() | ||
{ | ||
var service = new Mock<Service>(); | ||
service.As<IDisposable>() // Add IDisposable implementation for the mocked Service class. | ||
.Setup(s => s.Dispose()); | ||
service.As<OtherService>(); // An error will be raised, because we can't mock additional implementation of a class. | ||
} | ||
|
||
public abstract class Service | ||
{ | ||
} | ||
|
||
public abstract class OtherService | ||
{ | ||
} | ||
``` | ||
|
||
## How to fix violations | ||
|
||
To fix a violation of this rule, use an interface when using the `As<T>()` method. | ||
|
||
## When to suppress warnings | ||
|
||
Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `MoqException` | ||
thrown with the *"Can only add interfaces to the mock."* message. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# PosInfoMoq2008: The `Verify()` method must be used only on overridable members | ||
|
||
| Property | Value | | ||
|-------------------------------------|---------------------------------------------------------------| | ||
| **Rule ID** | PosInfoMoq2008 | | ||
| **Title** | The `Verify()` method must be used only on overridable members | | ||
| **Category** | Compilation | | ||
| **Default severity** | Error | | ||
|
||
## Cause | ||
|
||
The `Verify()` method must be applied only for overridable members. | ||
An overridable member is a **method** or **property** which is in: | ||
- An `interface`. | ||
- A non-`sealed` `class`. In this case, the member must be: | ||
- Defines as `abstract`. | ||
- Or defined as `virtual` | ||
|
||
## Rule description | ||
|
||
The `Verify()` method must be applied only for overridable members. | ||
|
||
For example, the following methods and properties can be mock and used in the `Verify()` method: | ||
- `IService.MethodCanBeMocked()` | ||
- `IService.PropertyCanBeMocked` | ||
- `Service.VirtualMethodCanBeMocked` | ||
- `Service.VirtualPropertyCanBeMocked` | ||
- `Service.AbstractMethodCanBeMocked` | ||
- `Service.AbstractPropertyCanBeMocked` | ||
|
||
```csharp | ||
public interface IService | ||
{ | ||
void MethodCanBeMocked(); | ||
|
||
string PropertyCanBeMocked { get; set; } | ||
} | ||
|
||
public abstract class Service | ||
{ | ||
public virtual void VirtualMethodCanBeMocked() { ... } | ||
|
||
public virtual void VirtualPropertyCanBeMocked() { ... } | ||
|
||
public abstract void AbstractMethodCanBeMocked(); | ||
|
||
public abstract void AbstractPropertyCanBeMocked(); | ||
} | ||
``` | ||
|
||
> **NOTE**: The extension methods can not be overriden. The C# syntax looks like a member method an interface or class, but the extension method are just simple | ||
static methods which can not be overriden. | ||
|
||
## How to fix violations | ||
|
||
To fix a violation of this rule, be sure to mock a member in the `Verify()` method which can be overriden. | ||
|
||
## When to suppress warnings | ||
|
||
Do not suppress an error from this rule. If bypassed, the execution of the unit test will be failed with a `MoqException` | ||
thrown with the *"Unsupported expression: m => m.Method(). Non-overridable members (here: Namespace.Class.Method) may not be used in setup / verification expressions."* message. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
src/Moq.Analyzers/Analyzers/AsMustBeUsedWithInterfaceAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
//----------------------------------------------------------------------- | ||
// <copyright file="AsMustBeUsedWithInterfaceAnalyzer.cs" company="P.O.S Informatique"> | ||
// Copyright (c) P.O.S Informatique. All rights reserved. | ||
// </copyright> | ||
//----------------------------------------------------------------------- | ||
|
||
namespace PosInformatique.Moq.Analyzers | ||
{ | ||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public class AsMustBeUsedWithInterfaceAnalyzer : DiagnosticAnalyzer | ||
{ | ||
internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( | ||
"PosInfoMoq2007", | ||
"The As<T>() method can be used only with interfaces", | ||
"The As<T>() method can be used only with interfaces", | ||
"Compilation", | ||
DiagnosticSeverity.Error, | ||
isEnabledByDefault: true, | ||
description: "The As<T>() method can be used only with interfaces.", | ||
helpLinkUri: "https://posinformatique.github.io/PosInformatique.Moq.Analyzers/docs/Compilation/PosInfoMoq2007.html"); | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
context.EnableConcurrentExecution(); | ||
|
||
context.RegisterSyntaxNodeAction(Analyze, SyntaxKind.InvocationExpression); | ||
} | ||
|
||
private static void Analyze(SyntaxNodeAnalysisContext context) | ||
{ | ||
var invocationExpression = (InvocationExpressionSyntax)context.Node; | ||
|
||
var moqSymbols = MoqSymbols.FromCompilation(context.Compilation); | ||
|
||
if (moqSymbols is null) | ||
{ | ||
return; | ||
} | ||
|
||
var moqExpressionAnalyzer = new MoqExpressionAnalyzer(moqSymbols, context.SemanticModel); | ||
|
||
var asMethodType = moqExpressionAnalyzer.ExtractAsMethodType(invocationExpression, out var typeSyntax, context.CancellationToken); | ||
|
||
if (asMethodType is null) | ||
{ | ||
return; | ||
} | ||
|
||
if (asMethodType.TypeKind == TypeKind.Interface) | ||
{ | ||
return; | ||
} | ||
|
||
var diagnostic = Diagnostic.Create(Rule, typeSyntax!.GetLocation()); | ||
context.ReportDiagnostic(diagnostic); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.