diff --git a/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldFailOnGenericTypesWithMismatchArgs.verified.txt b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldFailOnGenericTypesWithMismatchArgs.verified.txt new file mode 100644 index 000000000..9e7027cee --- /dev/null +++ b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldFailOnGenericTypesWithMismatchArgs.verified.txt @@ -0,0 +1,24 @@ +Diagnostic 1 + Id: Moq1002 + Location: SourceFile(Test0.cs[608..614)) + Highlight: ("42") + Lines: var mock = new Mock>("42"); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 2 + Id: Moq1002 + Location: SourceFile(Test0.cs[788..798)) + Highlight: ("42", 42) + Lines: var mock1 = new Mock>("42", 42); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 3 + Id: Moq1002 + Location: SourceFile(Test0.cs[934..938)) + Highlight: (42) + Lines: var mock2 = new Mock>(42); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + diff --git a/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldFailOnMismatchArgs.verified.txt b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldFailOnMismatchArgs.verified.txt new file mode 100644 index 000000000..e5cd7e3f0 --- /dev/null +++ b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldFailOnMismatchArgs.verified.txt @@ -0,0 +1,24 @@ +Diagnostic 1 + Id: Moq1002 + Location: SourceFile(Test0.cs[526..532)) + Highlight: ("42") + Lines: var mock = new Mock("42"); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 2 + Id: Moq1002 + Location: SourceFile(Test0.cs[691..701)) + Highlight: ("42", 42) + Lines: var mock1 = new Mock("42", 42); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 3 + Id: Moq1002 + Location: SourceFile(Test0.cs[822..826)) + Highlight: (42) + Lines: var mock2 = new Mock(42); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + diff --git a/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassIfGoodParametersAndFailOnTypeMismatch.verified.txt b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassIfGoodParametersAndFailOnTypeMismatch.verified.txt deleted file mode 100644 index a91dc11ae..000000000 --- a/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassIfGoodParametersAndFailOnTypeMismatch.verified.txt +++ /dev/null @@ -1,48 +0,0 @@ -Diagnostic 1 - Id: Moq1002 - Location: SourceFile(Test1.cs[223..229)) - Highlight: ("42") - Lines: var mock = new Mock("42"); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 2 - Id: Moq1002 - Location: SourceFile(Test1.cs[388..398)) - Highlight: ("42", 42) - Lines: var mock1 = new Mock("42", 42); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 3 - Id: Moq1002 - Location: SourceFile(Test1.cs[519..523)) - Highlight: (42) - Lines: var mock2 = new Mock(42); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 4 - Id: Moq1002 - Location: SourceFile(Test1.cs[720..726)) - Highlight: ("42") - Lines: var mock = new Mock>("42"); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 5 - Id: Moq1002 - Location: SourceFile(Test1.cs[900..910)) - Highlight: ("42", 42) - Lines: var mock1 = new Mock>("42", 42); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 6 - Id: Moq1002 - Location: SourceFile(Test1.cs[1046..1050)) - Highlight: (42) - Lines: var mock2 = new Mock>(42); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - diff --git a/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassOnGenericTypesWithNoArgs.verified.txt b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassOnGenericTypesWithNoArgs.verified.txt new file mode 100644 index 000000000..c1b8d743e --- /dev/null +++ b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassOnGenericTypesWithNoArgs.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassWithArgsPassed.verified.txt b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassWithArgsPassed.verified.txt new file mode 100644 index 000000000..c1b8d743e --- /dev/null +++ b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassWithArgsPassed.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassWithNoArgs.verified.txt b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassWithNoArgs.verified.txt new file mode 100644 index 000000000..c1b8d743e --- /dev/null +++ b/Source/Moq.Analyzers.Test/AbstractClassTests.ShouldPassWithNoArgs.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/AbstractClassTests.cs b/Source/Moq.Analyzers.Test/AbstractClassTests.cs index 13c87a922..0c60b2430 100644 --- a/Source/Moq.Analyzers.Test/AbstractClassTests.cs +++ b/Source/Moq.Analyzers.Test/AbstractClassTests.cs @@ -7,15 +7,234 @@ namespace Moq.Analyzers.Test; public class AbstractClassTests : DiagnosticVerifier { + // TODO: Review use of `.As<>()` in the test cases. It is not clear what purpose it serves. [Fact] - public Task ShouldPassIfGoodParametersAndFailOnTypeMismatch() + public Task ShouldFailOnGenericTypesWithMismatchArgs() { return Verify(VerifyCSharpDiagnostic( [ - File.ReadAllText("Data/AbstractClass.Good.cs"), - File.ReadAllText("Data/AbstractClass.Bad.cs") - ] - )); + """ + namespace Moq.Analyzers.Test.Data.AbstractClass.GenericMistmatchArgs; + + internal abstract class AbstractGenericClassDefaultCtor + { + protected AbstractGenericClassDefaultCtor() + { + } + } + + internal abstract class AbstractGenericClassWithCtor + { + protected AbstractGenericClassWithCtor(int a) + { + } + + protected AbstractGenericClassWithCtor(int a, string b) + { + } + } + + internal class MyUnitTests + { + private void TestBadWithGeneric() + { + // The class has a constructor that takes an Int32 but passes a String + var mock = new Mock>("42"); + + // The class has a ctor with two arguments [Int32, String], but they are passed in reverse order + var mock1 = new Mock>("42", 42); + + // The class has a ctor but does not take any arguments + var mock2 = new Mock>(42); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassOnGenericTypesWithNoArgs() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace Moq.Analyzers.Test.Data.AbstractClass.GenericNoArgs; + + internal abstract class AbstractGenericClassDefaultCtor + { + protected AbstractGenericClassDefaultCtor() + { + } + } + + internal class MyUnitTests + { + private void TestForBaseGenericNoArgs() + { + var mock = new Mock>(); + mock.As>(); + + var mock1 = new Mock>(); + + var mock2 = new Mock>(MockBehavior.Default); + } + } + """ + ])); + } + + [Fact] + public Task ShouldFailOnMismatchArgs() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace Moq.Analyzers.Test.Data.AbstractClass.MismatchArgs; + + internal abstract class AbstractClassDefaultCtor + { + protected AbstractClassDefaultCtor() + { + } + } + + internal abstract class AbstractClassWithCtor + { + protected AbstractClassWithCtor(int a) + { + } + + protected AbstractClassWithCtor(int a, string b) + { + } + } + + internal class MyUnitTests + { + private void TestBad() + { + // The class has a ctor that takes an Int32 but passes a String + var mock = new Mock("42"); + + // The class has a ctor with two arguments [Int32, String], but they are passed in reverse order + var mock1 = new Mock("42", 42); + + // The class has a ctor but does not take any arguments + var mock2 = new Mock(42); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWithNoArgs() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace Moq.Analyzers.Test.Data.AbstractClass.NoArgs; + + internal abstract class AbstractClassDefaultCtor + { + protected AbstractClassDefaultCtor() + { + } + } + + internal class MyUnitTests + { + // Base case that we can handle abstract types + private void TestForBaseNoArgs() + { + var mock = new Mock(); + mock.As(); + } + } + """ + ])); + } + + [Fact(Skip = "I think this _should_ fail, but currently passes. Tracked by #55.")] + public Task ShouldFailWithArgsNonePassed() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace Moq.Analyzers.Test.Data.AbstractClass.WithArgsNonePassed; + + internal abstract class AbstractClassWithCtor + { + protected AbstractClassWithCtor(int a) + { + } + + protected AbstractClassWithCtor(int a, string b) + { + } + } + + internal class MyUnitTests + { + // This is syntatically not allowed by C#, but you can do it with Moq + private void TestForBaseWithArgsNonePassed() + { + var mock = new Mock(); + mock.As(); + + var mock2 = new Mock(MockBehavior.Default); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWithArgsPassed() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace Moq.Analyzers.Test.DataAbstractClass.WithArgsPassed; + + internal abstract class AbstractGenericClassWithCtor + { + protected AbstractGenericClassWithCtor(int a) + { + } + + protected AbstractGenericClassWithCtor(int a, string b) + { + } + } + + internal abstract class AbstractClassWithCtor + { + protected AbstractClassWithCtor(int a) + { + } + + protected AbstractClassWithCtor(int a, string b) + { + } + } + + internal class MyUnitTests + { + private void TestForBaseWithArgsPassed() + { + var mock = new Mock(42); + var mock2 = new Mock(MockBehavior.Default, 42); + + var mock3 = new Mock(42, "42"); + var mock4 = new Mock(MockBehavior.Default, 42, "42"); + + var mock5 = new Mock>(42); + var mock6 = new Mock>(MockBehavior.Default, 42); + } + } + """ + ])); } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldFailWhenUsingAsWithAbstractClass.verified.txt b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldFailWhenUsingAsWithAbstractClass.verified.txt new file mode 100644 index 000000000..3207abdda --- /dev/null +++ b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldFailWhenUsingAsWithAbstractClass.verified.txt @@ -0,0 +1,8 @@ +Diagnostic 1 + Id: Moq1300 + Location: SourceFile(Test0.cs[292..307)) + Highlight: BaseSampleClass + Lines: mock.As(); + Severity: Error + Message: Mock.As() should take interfaces only + diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldFailWhenUsingAsWithConcreteClass.verified.txt b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldFailWhenUsingAsWithConcreteClass.verified.txt new file mode 100644 index 000000000..e54f2188e --- /dev/null +++ b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldFailWhenUsingAsWithConcreteClass.verified.txt @@ -0,0 +1,8 @@ +Diagnostic 1 + Id: Moq1300 + Location: SourceFile(Test0.cs[433..443)) + Highlight: OtherClass + Lines: mock.As(); + Severity: Error + Message: Mock.As() should take interfaces only + diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassIfGoodParameters.verified.txt b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassIfGoodParameters.verified.txt deleted file mode 100644 index b61e0229b..000000000 --- a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassIfGoodParameters.verified.txt +++ /dev/null @@ -1,16 +0,0 @@ -Diagnostic 1 - Id: Moq1300 - Location: SourceFile(Test0.cs[1212..1227)) - Highlight: BaseSampleClass - Lines: mock.As(); - Severity: Error - Message: Mock.As() should take interfaces only - -Diagnostic 2 - Id: Moq1300 - Location: SourceFile(Test0.cs[1357..1367)) - Highlight: OtherClass - Lines: mock.As(); - Severity: Error - Message: Mock.As() should take interfaces only - diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassWhenUsingAsWithInterface.verified.txt b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassWhenUsingAsWithInterface.verified.txt new file mode 100644 index 000000000..c1b8d743e --- /dev/null +++ b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassWhenUsingAsWithInterface.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassWhenUsingAsWithInterfaceWithSetup.verified.txt b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassWhenUsingAsWithInterfaceWithSetup.verified.txt new file mode 100644 index 000000000..c1b8d743e --- /dev/null +++ b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.ShouldPassWhenUsingAsWithInterfaceWithSetup.verified.txt @@ -0,0 +1 @@ +emptyString \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs index 9e273482b..b1295ffc7 100644 --- a/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/AsAcceptOnlyInterfaceAnalyzerTests.cs @@ -9,9 +9,134 @@ namespace Moq.Analyzers.Test; public class AsAcceptOnlyInterfaceAnalyzerTests : DiagnosticVerifier { [Fact] - public Task ShouldPassIfGoodParameters() + public Task ShouldFailWhenUsingAsWithAbstractClass() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/AsAcceptOnlyInterface.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace AsAcceptOnlyInterface.TestBadAsForAbstractClass; + + public abstract class BaseSampleClass + { + public int Calculate() => 0; + } + + internal class MyUnitTests + { + private void TestBadAsForAbstractClass() + { + var mock = new Mock(); + mock.As(); + } + } + """ + ])); + } + + [Fact] + public Task ShouldFailWhenUsingAsWithConcreteClass() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace AsAcceptOnlyInterface.TestBadAsForNonAbstractClass; + + public interface ISampleInterface + { + int Calculate(int a, int b); + } + + public abstract class BaseSampleClass + { + public int Calculate() => 0; + } + + public class OtherClass + { + + public int Calculate() => 0; + } + + internal class MyUnitTests + { + private void TestBadAsForNonAbstractClass() + { + var mock = new Mock(); + mock.As(); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenUsingAsWithInterface() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace AsAcceptOnlyInterface.TestOkAsForInterface; + + public interface ISampleInterface + { + int Calculate(int a, int b); + } + + public class SampleClass + { + public int Calculate() => 0; + } + + internal class MyUnitTests + { + private void TestOkAsForInterface() + { + var mock = new Mock(); + mock.As(); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenUsingAsWithInterfaceWithSetup() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace AsAcceptOnlyInterface.TestOkAsForInterfaceWithConfiguration; + + public interface ISampleInterface + { + int Calculate(int a, int b); + } + + public class SampleClass + { + public int Calculate() => 0; + } + + internal class MyUnitTests + { + private void TestOkAsForInterfaceWithConfiguration() + { + var mock = new Mock(); + mock.As() + .Setup(x => x.Calculate(It.IsAny(), It.IsAny())) + .Returns(10); + } + } + """ + ])); } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassIfGoodParameters.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldFailWhenIncorrectCallbacks.verified.txt similarity index 84% rename from Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassIfGoodParameters.verified.txt rename to Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldFailWhenIncorrectCallbacks.verified.txt index 3de4ad679..bfaeee0cc 100644 --- a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassIfGoodParameters.verified.txt +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldFailWhenIncorrectCallbacks.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1100 - Location: SourceFile(Test0.cs[1030..1037)) + Location: SourceFile(Test0.cs[420..427)) Highlight: (int i) Lines: mock.Setup(x => x.Do(It.IsAny())).Callback((int i) => { }); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1100 - Location: SourceFile(Test0.cs[1106..1128)) + Location: SourceFile(Test0.cs[496..518)) Highlight: (string s1, string s2) Lines: mock.Setup(x => x.Do(It.IsAny())).Callback((string s1, string s2) => { }); Severity: Warning @@ -16,7 +16,7 @@ Diagnostic 2 Diagnostic 3 Id: Moq1100 - Location: SourceFile(Test0.cs[1236..1255)) + Location: SourceFile(Test0.cs[626..645)) Highlight: (string s1, int i1) Lines: mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((string s1, int i1) => { }); Severity: Warning @@ -24,7 +24,7 @@ Diagnostic 3 Diagnostic 4 Id: Moq1100 - Location: SourceFile(Test0.cs[1330..1337)) + Location: SourceFile(Test0.cs[720..727)) Highlight: (int i) Lines: mock.Setup(x => x.Do(It.IsAny>())).Callback((int i) => { }); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndCallbacks.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndCallbacks.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndCallbacks.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndParameterlessCallbacks.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndParameterlessCallbacks.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndParameterlessCallbacks.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndReturns.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndReturns.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndReturns.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndReturnsAndCallbacks.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndReturnsAndCallbacks.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.ShouldPassWhenCorrectSetupAndReturnsAndCallbacks.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs index fab69a812..cfe825e8b 100644 --- a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodAnalyzerTests.cs @@ -1,21 +1,38 @@ using System.IO; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; -using TestHelper; using Xunit; namespace Moq.Analyzers.Test; -public class CallbackSignatureShouldMatchMockedMethodAnalyzerTests : DiagnosticVerifier +public class CallbackSignatureShouldMatchMockedMethodAnalyzerTests : CallbackSignatureShouldMatchMockedMethodBase { [Fact] - public Task ShouldPassIfGoodParameters() + public Task ShouldPassWhenCorrectSetupAndReturns() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/CallbackSignatureShouldMatchMockedMethod.cs"))); + return Verify(VerifyCSharpDiagnostic(GoodSetupAndCallback)); } - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + [Fact] + public Task ShouldFailWhenIncorrectCallbacks() + { + return Verify(VerifyCSharpDiagnostic(BadCallbacks)); + } + + [Fact] + public Task ShouldPassWhenCorrectSetupAndCallbacks() + { + return Verify(VerifyCSharpDiagnostic(GoodSetupAndCallback)); + } + + [Fact] + public Task ShouldPassWhenCorrectSetupAndParameterlessCallbacks() + { + return Verify(VerifyCSharpDiagnostic(GoodSetupAndParameterlessCallback)); + } + + [Fact] + public Task ShouldPassWhenCorrectSetupAndReturnsAndCallbacks() { - return new CallbackSignatureShouldMatchMockedMethodAnalyzer(); + return Verify(VerifyCSharpDiagnostic(GoodSetupAndReturnsAndCallback)); } } diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodBase.cs b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodBase.cs new file mode 100644 index 000000000..87a09ebe3 --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodBase.cs @@ -0,0 +1,166 @@ +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using TestHelper; + +namespace Moq.Analyzers.Test; + +// TODO: These tests should be broken down further +// TODO: Merge the diagnostic and codefix tests into a single harness +public abstract class CallbackSignatureShouldMatchMockedMethodBase : CodeFixVerifier +{ + protected string GoodSetupAndReturns { get; } = + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace CallbackSignatureShouldMatchMockedMethod.MyGoodSetupAndReturns; + + internal interface IFoo + { + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); + } + + internal class MyUnitTests + { + private void MyGoodSetupAndReturns() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Returns((string s) => { return 0; }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns((int i, string s, DateTime dt) => { return 0; }); + mock.Setup(x => x.Do(It.IsAny>())).Returns((List l) => { return 0; }); + } + } + """; + + protected string BadCallbacks { get; } = + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace CallbackSignatureShouldMatchMockedMethod.TestBadCallbacks; + + internal interface IFoo + { + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); + } + + internal class MyUnitTests + { + private void TestBadCallbacks() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback((int i) => { }); + mock.Setup(x => x.Do(It.IsAny())).Callback((string s1, string s2) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((string s1, int i1) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback((int i) => { }); + } + } + """; + + protected string GoodSetupAndCallback { get; } = + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace CallbackSignatureShouldMatchMockedMethod.TestGoodSetupAndCallback; + + internal interface IFoo + { + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); + } + + internal class MyUnitTests + { + private void TestGoodSetupAndCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); + } + } + """; + + protected string GoodSetupAndParameterlessCallback { get; } = + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace CallbackSignatureShouldMatchMockedMethod.TestGoodSetupAndParameterlessCallback; + + internal interface IFoo + { + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); + } + + internal class MyUnitTests + { + private void TestGoodSetupAndParameterlessCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback(() => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback(() => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback(() => { }); + } + } + """; + + protected string GoodSetupAndReturnsAndCallback { get; } = + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace CallbackSignatureShouldMatchMockedMethod.TestGoodSetupAndReturnsAndCallback; + + internal interface IFoo + { + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); + } + + internal class MyUnitTests + { + private void TestGoodSetupAndReturnsAndCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Returns(0).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns(0).Callback((int i, string s, DateTime dt) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Returns(0).Callback((List l) => { }); + } + } + """; + + protected override CodeFixProvider GetCSharpCodeFixProvider() + { + return new CallbackSignatureShouldMatchMockedMethodCodeFix(); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new CallbackSignatureShouldMatchMockedMethodAnalyzer(); + } +} diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndCallbacks.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndCallbacks.verified.txt new file mode 100644 index 000000000..80913877d --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndCallbacks.verified.txt @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Moq; + +namespace CallbackSignatureShouldMatchMockedMethod.TestGoodSetupAndCallback; + +internal interface IFoo +{ + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); +} + +internal class MyUnitTests +{ + private void TestGoodSetupAndCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); + } +} diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndParameterlessCallbacks.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndParameterlessCallbacks.verified.txt new file mode 100644 index 000000000..ccd5ce3ed --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndParameterlessCallbacks.verified.txt @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Moq; + +namespace CallbackSignatureShouldMatchMockedMethod.TestGoodSetupAndParameterlessCallback; + +internal interface IFoo +{ + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); +} + +internal class MyUnitTests +{ + private void TestGoodSetupAndParameterlessCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback(() => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback(() => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback(() => { }); + } +} diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndReturns.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndReturns.verified.txt new file mode 100644 index 000000000..756d8892c --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndReturns.verified.txt @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Moq; + +namespace CallbackSignatureShouldMatchMockedMethod.MyGoodSetupAndReturns; + +internal interface IFoo +{ + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); +} + +internal class MyUnitTests +{ + private void MyGoodSetupAndReturns() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Returns((string s) => { return 0; }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns((int i, string s, DateTime dt) => { return 0; }); + mock.Setup(x => x.Do(It.IsAny>())).Returns((List l) => { return 0; }); + } +} diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndReturnsAndCallbacks.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndReturnsAndCallbacks.verified.txt new file mode 100644 index 000000000..17f6b9040 --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldPassWhenCorrectSetupAndReturnsAndCallbacks.verified.txt @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using Moq; + +namespace CallbackSignatureShouldMatchMockedMethod.TestGoodSetupAndReturnsAndCallback; + +internal interface IFoo +{ + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); +} + +internal class MyUnitTests +{ + private void TestGoodSetupAndReturnsAndCallback() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Returns(0).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns(0).Callback((int i, string s, DateTime dt) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Returns(0).Callback((List l) => { }); + } +} diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldSuggestQuickFixIfBadParameters.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldSuggestQuickFixIfBadParameters.verified.txt deleted file mode 100644 index 657e26825..000000000 --- a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldSuggestQuickFixIfBadParameters.verified.txt +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1021 // Simplify lambda expression -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace CallbackSignatureShouldMatchMockedMethod; - -internal interface IFoo -{ - int Do(string s); - - int Do(int i, string s, DateTime dt); - - int Do(List l); -} - -internal class MyUnitTests -{ - private void TestBadCallbacks() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); - } - - private void TestGoodSetupAndParameterlessCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback(() => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback(() => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback(() => { }); - } - - private void TestGoodSetupAndCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); - } - - private void TestGoodSetupAndReturnsAndCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Returns(0).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns(0).Callback((int i, string s, DateTime dt) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Returns(0).Callback((List l) => { }); - } - - private void MyGoodSetupAndReturns() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Returns((string s) => { return 0; }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns((int i, string s, DateTime dt) => { return 0; }); - mock.Setup(x => x.Do(It.IsAny>())).Returns((List l) => { return 0; }); - } -} diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldSuggestQuickFixWhenIncorrectCallbacks.verified.txt b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldSuggestQuickFixWhenIncorrectCallbacks.verified.txt new file mode 100644 index 000000000..2ae7ce25b --- /dev/null +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.ShouldSuggestQuickFixWhenIncorrectCallbacks.verified.txt @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using Moq; + +namespace CallbackSignatureShouldMatchMockedMethod.TestBadCallbacks; + +internal interface IFoo +{ + int Do(string s); + + int Do(int i, string s, DateTime dt); + + int Do(List l); +} + +internal class MyUnitTests +{ + private void TestBadCallbacks() + { + var mock = new Mock(); + mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); + mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); + mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); + } +} diff --git a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs index 4f5c99879..49221e4df 100644 --- a/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs +++ b/Source/Moq.Analyzers.Test/CallbackSignatureShouldMatchMockedMethodCodeFixTests.cs @@ -7,21 +7,35 @@ namespace Moq.Analyzers.Test; -public class CallbackSignatureShouldMatchMockedMethodCodeFixTests : CodeFixVerifier +public class CallbackSignatureShouldMatchMockedMethodCodeFixTests : CallbackSignatureShouldMatchMockedMethodBase { [Fact] - public Task ShouldSuggestQuickFixIfBadParameters() + public Task ShouldPassWhenCorrectSetupAndReturns() { - return Verify(VerifyCSharpFix(File.ReadAllText("Data/CallbackSignatureShouldMatchMockedMethod.cs"))); + return Verify(VerifyCSharpFix(GoodSetupAndReturns)); } - protected override CodeFixProvider GetCSharpCodeFixProvider() + [Fact] + public Task ShouldSuggestQuickFixWhenIncorrectCallbacks() + { + return Verify(VerifyCSharpFix(BadCallbacks)); + } + + [Fact] + public Task ShouldPassWhenCorrectSetupAndCallbacks() { - return new CallbackSignatureShouldMatchMockedMethodCodeFix(); + return Verify(VerifyCSharpFix(GoodSetupAndCallback)); } - protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + [Fact] + public Task ShouldPassWhenCorrectSetupAndParameterlessCallbacks() + { + return Verify(VerifyCSharpFix(GoodSetupAndParameterlessCallback)); + } + + [Fact] + public Task ShouldPassWhenCorrectSetupAndReturnsAndCallbacks() { - return new CallbackSignatureShouldMatchMockedMethodAnalyzer(); + return Verify(VerifyCSharpFix(GoodSetupAndReturnsAndCallback)); } } diff --git a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailIfClassParametersDoNotMatch.verified.txt b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailIfClassParametersDoNotMatch.verified.txt deleted file mode 100644 index 12a110935..000000000 --- a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailIfClassParametersDoNotMatch.verified.txt +++ /dev/null @@ -1,56 +0,0 @@ -Diagnostic 1 - Id: Moq1002 - Location: SourceFile(Test0.cs[1167..1176)) - Highlight: (1, true) - Lines: var mock1 = new Moq.Mock(1, true); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 2 - Id: Moq1002 - Location: SourceFile(Test0.cs[1243..1252)) - Highlight: (2, true) - Lines: var mock2 = new Mock(2, true); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 3 - Id: Moq1002 - Location: SourceFile(Test0.cs[1319..1327)) - Highlight: ("1", 3) - Lines: var mock3 = new Mock("1", 3); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 4 - Id: Moq1002 - Location: SourceFile(Test0.cs[1394..1417)) - Highlight: (new int[] { 1, 2, 3 }) - Lines: var mock4 = new Mock(new int[] { 1, 2, 3 }); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 5 - Id: Moq1002 - Location: SourceFile(Test0.cs[1493..1523)) - Highlight: (MockBehavior.Strict, 4, true) - Lines: var mock1 = new Mock(MockBehavior.Strict, 4, true); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 6 - Id: Moq1002 - Location: SourceFile(Test0.cs[1594..1623)) - Highlight: (MockBehavior.Loose, 5, true) - Lines: var mock2 = new Moq.Mock(MockBehavior.Loose, 5, true); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - -Diagnostic 7 - Id: Moq1002 - Location: SourceFile(Test0.cs[1694..1722)) - Highlight: (MockBehavior.Loose, "2", 6) - Lines: var mock3 = new Moq.Mock(MockBehavior.Loose, "2", 6); - Severity: Warning - Message: Parameters provided into mock do not match any existing constructors. - diff --git a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailWhenConstructorArumentsDoNotMatch.verified.txt b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailWhenConstructorArumentsDoNotMatch.verified.txt new file mode 100644 index 000000000..17eea554b --- /dev/null +++ b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailWhenConstructorArumentsDoNotMatch.verified.txt @@ -0,0 +1,32 @@ +Diagnostic 1 + Id: Moq1002 + Location: SourceFile(Test0.cs[392..401)) + Highlight: (1, true) + Lines: var mock1 = new Mock(1, true); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 2 + Id: Moq1002 + Location: SourceFile(Test0.cs[436..445)) + Highlight: (2, true) + Lines: var mock2 = new Mock(2, true); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 3 + Id: Moq1002 + Location: SourceFile(Test0.cs[480..488)) + Highlight: ("1", 3) + Lines: var mock3 = new Mock("1", 3); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 4 + Id: Moq1002 + Location: SourceFile(Test0.cs[523..546)) + Highlight: (new int[] { 1, 2, 3 }) + Lines: var mock4 = new Mock(new int[] { 1, 2, 3 }); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + diff --git a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailWhenConstructorArumentsWithExplicitMockBehaviorDoNotMatch.verified.txt b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailWhenConstructorArumentsWithExplicitMockBehaviorDoNotMatch.verified.txt new file mode 100644 index 000000000..1976d03e7 --- /dev/null +++ b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldFailWhenConstructorArumentsWithExplicitMockBehaviorDoNotMatch.verified.txt @@ -0,0 +1,24 @@ +Diagnostic 1 + Id: Moq1002 + Location: SourceFile(Test0.cs[423..453)) + Highlight: (MockBehavior.Strict, 4, true) + Lines: var mock1 = new Mock(MockBehavior.Strict, 4, true); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 2 + Id: Moq1002 + Location: SourceFile(Test0.cs[488..517)) + Highlight: (MockBehavior.Loose, 5, true) + Lines: var mock2 = new Mock(MockBehavior.Loose, 5, true); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + +Diagnostic 3 + Id: Moq1002 + Location: SourceFile(Test0.cs[552..580)) + Highlight: (MockBehavior.Loose, "2", 6) + Lines: var mock3 = new Mock(MockBehavior.Loose, "2", 6); + Severity: Warning + Message: Parameters provided into mock do not match any existing constructors. + diff --git a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldPassWhenConstructorArgumentsMatch.verified.txt b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldPassWhenConstructorArgumentsMatch.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.ShouldPassWhenConstructorArgumentsMatch.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs index de7a63d89..d825fbb3f 100644 --- a/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/ConstructorArgumentsShouldMatchAnalyzerTests.cs @@ -9,16 +9,130 @@ namespace Moq.Analyzers.Test; public class ConstructorArgumentsShouldMatchAnalyzerTests : DiagnosticVerifier { [Fact] - public Task ShouldFailIfClassParametersDoNotMatch() + public Task ShouldPassWhenConstructorArgumentsMatch() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/ConstructorArgumentsShouldMatch.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace ConstructorArgumentsShouldMatch.TestGood; + + internal class Foo + { + public Foo(string s) { } + + public Foo(bool b, int i) { } + + public Foo(params DateTime[] dates) { } + + public Foo(List l, string s = "A") { } + } + + internal class MyUnitTests + { + private void TestGood() + { + var mock1 = new Mock(MockBehavior.Default); + var mock2 = new Mock(MockBehavior.Strict); + var mock3 = new Mock(MockBehavior.Loose); + var mock4 = new Mock(MockBehavior.Default); + + var mock5 = new Mock("3"); + var mock6 = new Mock("4"); + var mock7 = new Mock(MockBehavior.Default, "5"); + var mock8 = new Mock(MockBehavior.Default, "6"); + + var mock9 = new Mock(false, 0); + var mock10 = new Mock(MockBehavior.Default, true, 1); + + var mock11 = new Mock(DateTime.Now, DateTime.Now); + var mock12 = new Mock(MockBehavior.Default, DateTime.Now, DateTime.Now); + + var mock13 = new Mock(new List(), "7"); + var mock14 = new Mock(new List()); + var mock15 = new Mock(MockBehavior.Default, new List(), "8"); + var mock16 = new Mock(MockBehavior.Default, new List()); + } + } + """ + ])); } - // [Fact] - // public Task ShouldPassIfCustomMockClassIsUsed() - // { - // return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/MockInterfaceWithParametersCustomMockFile.cs"))); - // } + [Fact] + public Task ShouldFailWhenConstructorArumentsDoNotMatch() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace ConstructorArgumentsShouldMatch.TestBad; + + internal class Foo + { + public Foo(string s) { } + + public Foo(bool b, int i) { } + + public Foo(params DateTime[] dates) { } + + public Foo(List l, string s = "A") { } + } + + internal class MyUnitTests + { + private void TestBad() + { + var mock1 = new Mock(1, true); + var mock2 = new Mock(2, true); + var mock3 = new Mock("1", 3); + var mock4 = new Mock(new int[] { 1, 2, 3 }); + } + } + """ + ])); + } + + [Fact] + public Task ShouldFailWhenConstructorArumentsWithExplicitMockBehaviorDoNotMatch() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System; + using System.Collections.Generic; + using Moq; + + namespace ConstructorArgumentsShouldMatchTestBadWithMockBehavior; + + internal class Foo + { + public Foo(string s) { } + + public Foo(bool b, int i) { } + + public Foo(params DateTime[] dates) { } + + public Foo(List l, string s = "A") { } + } + + internal class MyUnitTests + { + private void TestBadWithMockBehavior() + { + var mock1 = new Mock(MockBehavior.Strict, 4, true); + var mock2 = new Mock(MockBehavior.Loose, 5, true); + var mock3 = new Mock(MockBehavior.Loose, "2", 6); + } + } + """ + ])); + } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() { diff --git a/Source/Moq.Analyzers.Test/Data/AbstractClass.Bad.cs b/Source/Moq.Analyzers.Test/Data/AbstractClass.Bad.cs deleted file mode 100644 index 4945e7e17..000000000 --- a/Source/Moq.Analyzers.Test/Data/AbstractClass.Bad.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Moq.Analyzers.Test.Data; - -internal class MyBadUnitTests -{ - private void TestBad() - { - // The class has a ctor that takes an Int32 but passes a String - var mock = new Mock("42"); - - // The class has a ctor with two arguments [Int32, String], but they are passed in reverse order - var mock1 = new Mock("42", 42); - - // The class has a ctor but does not take any arguments - var mock2 = new Mock(42); - } - - private void TestBadWithGeneric() - { - // The class has a constructor that takes an Int32 but passes a String - var mock = new Mock>("42"); - - // The class has a ctor with two arguments [Int32, String], but they are passed in reverse order - var mock1 = new Mock>("42", 42); - - // The class has a ctor but does not take any arguments - var mock2 = new Mock>(42); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/AbstractClass.Good.cs b/Source/Moq.Analyzers.Test/Data/AbstractClass.Good.cs deleted file mode 100644 index 0b61bc3bb..000000000 --- a/Source/Moq.Analyzers.Test/Data/AbstractClass.Good.cs +++ /dev/null @@ -1,79 +0,0 @@ -namespace Moq.Analyzers.Test.Data; - -internal abstract class AbstractGenericClassDefaultCtor -{ - protected AbstractGenericClassDefaultCtor() - { - } -} - -internal abstract class AbstractGenericClassWithCtor -{ - protected AbstractGenericClassWithCtor(int a) - { - } - - protected AbstractGenericClassWithCtor(int a, string b) - { - } -} - -internal abstract class AbstractClassDefaultCtor -{ - protected AbstractClassDefaultCtor() - { - } -} - -internal abstract class AbstractClassWithCtor -{ - protected AbstractClassWithCtor(int a) - { - } - - protected AbstractClassWithCtor(int a, string b) - { - } -} - -internal class MyUnitTests -{ - // Base case that we can handle abstract types - private void TestForBaseNoArgs() - { - var mock = new Mock(); - mock.As(); - - var mock2 = new Mock(); - var mock3 = new Mock(MockBehavior.Default); - } - - private void TestForBaseGenericNoArgs() - { - var mock = new Mock>(); - mock.As>(); - - var mock1 = new Mock>(); - - var mock2 = new Mock>(MockBehavior.Default); - } - - // This is syntatically not allowed by C#, but you can do it with Moq - private void TestForBaseWithArgsNonePassed() - { - var mock = new Mock(); - mock.As(); - } - - private void TestForBaseWithArgsPassed() - { - var mock = new Mock(42); - var mock2 = new Mock(MockBehavior.Default, 42); - - var mock3 = new Mock(42, "42"); - var mock4 = new Mock(MockBehavior.Default, 42, "42"); - - var mock5 = new Mock>(42); - var mock6 = new Mock>(MockBehavior.Default, 42); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/AsAcceptOnlyInterface.cs b/Source/Moq.Analyzers.Test/Data/AsAcceptOnlyInterface.cs deleted file mode 100644 index deeff3463..000000000 --- a/Source/Moq.Analyzers.Test/Data/AsAcceptOnlyInterface.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable SA1502 // Element must not be on a single line -namespace AsAcceptOnlyInterface; - -public interface ISampleInterface -{ - int Calculate(int a, int b); - - int TestProperty { get; set; } -} - -public abstract class BaseSampleClass -{ - public int Calculate() - { - return 0; - } - - public abstract int Calculate(int a, int b, int c); -} - -public class SampleClass -{ - - public virtual int Calculate(int a, int b) => 0; -} - -public class OtherClass -{ - - public virtual int Calculate() => 0; -} - -internal class MyUnitTests -{ - private void TestOkAsForInterface() - { - var mock = new Mock(); - mock.As(); - } - - private void TestOkAsForInterfaceWithConfiguration() - { - var mock = new Mock(); - mock.As() - .Setup(x => x.Calculate(It.IsAny(), It.IsAny())) - .Returns(10); - } - - private void TestBadAsForAbstractClass() - { - var mock = new Mock(); - mock.As(); - } - - private void TestBadAsForNonAbstractClass() - { - var mock = new Mock(); - mock.As(); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/CallbackSignatureShouldMatchMockedMethod.cs b/Source/Moq.Analyzers.Test/Data/CallbackSignatureShouldMatchMockedMethod.cs deleted file mode 100644 index 48bab2ba3..000000000 --- a/Source/Moq.Analyzers.Test/Data/CallbackSignatureShouldMatchMockedMethod.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1021 // Simplify lambda expression -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace CallbackSignatureShouldMatchMockedMethod; - -internal interface IFoo -{ - int Do(string s); - - int Do(int i, string s, DateTime dt); - - int Do(List l); -} - -internal class MyUnitTests -{ - private void TestBadCallbacks() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback((int i) => { }); - mock.Setup(x => x.Do(It.IsAny())).Callback((string s1, string s2) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((string s1, int i1) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback((int i) => { }); - } - - private void TestGoodSetupAndParameterlessCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback(() => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback(() => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback(() => { }); - } - - private void TestGoodSetupAndCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Callback((int i, string s, DateTime dt) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Callback((List l) => { }); - } - - private void TestGoodSetupAndReturnsAndCallback() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Returns(0).Callback((string s) => { }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns(0).Callback((int i, string s, DateTime dt) => { }); - mock.Setup(x => x.Do(It.IsAny>())).Returns(0).Callback((List l) => { }); - } - - private void MyGoodSetupAndReturns() - { - var mock = new Mock(); - mock.Setup(x => x.Do(It.IsAny())).Returns((string s) => { return 0; }); - mock.Setup(x => x.Do(It.IsAny(), It.IsAny(), It.IsAny())).Returns((int i, string s, DateTime dt) => { return 0; }); - mock.Setup(x => x.Do(It.IsAny>())).Returns((List l) => { return 0; }); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/ConstructorArgumentsShouldMatch.cs b/Source/Moq.Analyzers.Test/Data/ConstructorArgumentsShouldMatch.cs deleted file mode 100644 index 27c782e37..000000000 --- a/Source/Moq.Analyzers.Test/Data/ConstructorArgumentsShouldMatch.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1160 // Public constructor in abstract class -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace ConstructorArgumentsShouldMatch; - -#pragma warning disable SA1402 // File may only contain a single class -internal class Foo -{ - public Foo(string s) { } - - public Foo(bool b, int i) { } - - public Foo(params DateTime[] dates) { } - - public Foo(List l, string s = "A") { } -} - -internal class MyUnitTests -#pragma warning restore SA1402 // File may only contain a single class -{ - private void TestBad() - { - var mock1 = new Moq.Mock(1, true); - var mock2 = new Mock(2, true); - var mock3 = new Mock("1", 3); - var mock4 = new Mock(new int[] { 1, 2, 3 }); - } - - private void TestBad2() - { - var mock1 = new Mock(MockBehavior.Strict, 4, true); - var mock2 = new Moq.Mock(MockBehavior.Loose, 5, true); - var mock3 = new Moq.Mock(MockBehavior.Loose, "2", 6); - } - - private void TestGood1() - { - var mock1 = new Moq.Mock(MockBehavior.Default); - var mock2 = new Mock(MockBehavior.Strict); - var mock3 = new Mock(MockBehavior.Loose); - var mock4 = new Moq.Mock(MockBehavior.Default); - - var mock5 = new Mock("3"); - var mock6 = new Moq.Mock("4"); - var mock7 = new Moq.Mock(Moq.MockBehavior.Default, "5"); - var mock8 = new Mock(Moq.MockBehavior.Default, "6"); - - var mock9 = new Moq.Mock(false, 0); - var mock10 = new Moq.Mock(Moq.MockBehavior.Default, true, 1); - - var mock11 = new Mock(DateTime.Now, DateTime.Now); - var mock12 = new Mock(MockBehavior.Default, DateTime.Now, DateTime.Now); - - var mock13 = new Mock(new List(), "7"); - var mock14 = new Mock(new List()); - var mock15 = new Mock(MockBehavior.Default, new List(), "8"); - var mock16 = new Mock(MockBehavior.Default, new List()); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_1.cs b/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_1.cs deleted file mode 100644 index 656ef2fcb..000000000 --- a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_1.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoConstructorArgumentsForInterfaceMock_1; - -internal interface IMyService -{ - void Do(string s); -} - -internal class MyUnitTests -{ - private void TestBad() - { - var mock1 = new Moq.Mock(25, true); - var mock2 = new Mock("123"); - var mock3 = new Mock(25, true); - var mock4 = new Moq.Mock("123"); - } - - private void TestBad2() - { - var mock1 = new Moq.Mock(Moq.MockBehavior.Default, "123"); - var mock2 = new Mock(MockBehavior.Strict, 25, true); - var mock3 = new Mock(Moq.MockBehavior.Default, "123"); - var mock4 = new Moq.Mock(MockBehavior.Loose, 25, true); - } - - private void TestGood1() - { - var mock1 = new Moq.Mock(); - var mock2 = new Moq.Mock(MockBehavior.Default); - var mock3 = new Mock(MockBehavior.Strict); - var mock4 = new Mock(MockBehavior.Loose); - var mock5 = new Moq.Mock(MockBehavior.Default); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_2.cs b/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_2.cs deleted file mode 100644 index 65c9cbcac..000000000 --- a/Source/Moq.Analyzers.Test/Data/NoConstructorArgumentsForInterfaceMock_2.cs +++ /dev/null @@ -1,63 +0,0 @@ -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoConstructorArgumentsForInterfaceMock_2; - -public enum MockBehavior -{ - Default, - Strict, - Loose, -} - -internal interface IMyService -{ - void Do(string s); -} - -public class Mock - where T : class -{ - public Mock() { } - - public Mock(params object[] ar) { } - - public Mock(MockBehavior behavior) { } - - public Mock(MockBehavior behavior, params object[] args) { } -} - -internal class MyUnitTests -{ - private void TestRealMoqWithBadParameters() - { - var mock1 = new Moq.Mock(1, true); - var mock2 = new Moq.Mock("2"); - var mock3 = new Moq.Mock(Moq.MockBehavior.Default, "3"); - var mock4 = new Moq.Mock(MockBehavior.Loose, 4, true); - var mock5 = new Moq.Mock(MockBehavior.Default); - var mock6 = new Moq.Mock(MockBehavior.Default); - } - - private void TestRealMoqWithGoodParameters() - { - var mock1 = new Moq.Mock(Moq.MockBehavior.Default); - var mock2 = new Moq.Mock(Moq.MockBehavior.Default); - } - - private void TestFakeMoq() - { - var mock1 = new Mock("4"); - var mock2 = new Mock(5, true); - var mock3 = new Mock(MockBehavior.Strict, 6, true); - var mock4 = new Mock(Moq.MockBehavior.Default, "5"); - var mock5 = new Mock(MockBehavior.Strict); - var mock6 = new Mock(MockBehavior.Loose); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/NoMethodsInPropertySetup.cs b/Source/Moq.Analyzers.Test/Data/NoMethodsInPropertySetup.cs deleted file mode 100644 index 7db851242..000000000 --- a/Source/Moq.Analyzers.Test/Data/NoMethodsInPropertySetup.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoMethodsInPropertySetup; - -public interface IFoo -{ - string Prop1 { get; set; } - - string Prop2 { get; } - - string Prop3 { set; } - - string Method(); -} - -public class MyUnitTests -{ - private void TestBad() - { - var mock = new Mock(); - mock.SetupGet(x => x.Method()); - mock.SetupSet(x => x.Method()); - } - - private void TestGood() - { - var mock = new Mock(); - mock.SetupGet(x => x.Prop1); - mock.SetupGet(x => x.Prop2); - mock.SetupSet(x => x.Prop1 = "1"); - mock.SetupSet(x => x.Prop3 = "2"); - mock.Setup(x => x.Method()); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/NoSealedClassMocks.cs b/Source/Moq.Analyzers.Test/Data/NoSealedClassMocks.cs deleted file mode 100644 index c31f778d8..000000000 --- a/Source/Moq.Analyzers.Test/Data/NoSealedClassMocks.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1502 // Element must not be on a single line -#pragma warning disable SA1602 // Undocumented enum values -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable RCS1163 // Unused parameter -#pragma warning disable RCS1213 // Remove unused member declaration -#pragma warning disable IDE0051 // Unused private member -#pragma warning disable IDE0059 // Unnecessary value assignment -#pragma warning disable IDE0060 // Unused parameter -namespace NoSealedClassMocks; - -internal sealed class FooSealed -{ - private void Do(string s) { } -} - -internal class MyUnitTests -{ - private void Test() - { - var mock1 = new Moq.Mock(); - var mock2 = new Mock(); - var mock3 = new Mock(); - var mock4 = new Moq.Mock(); - } - - private void Test2() - { - new Mock>(); - new Mock(); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/SetupOnlyForOverridableMembers.cs b/Source/Moq.Analyzers.Test/Data/SetupOnlyForOverridableMembers.cs deleted file mode 100644 index 8a79ffd14..000000000 --- a/Source/Moq.Analyzers.Test/Data/SetupOnlyForOverridableMembers.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable SA1502 // Element must not be on a single line -namespace SetupOnlyForOverridableMembers; - -public interface ISampleInterface -{ - int Calculate(int a, int b); - - int TestProperty { get; set; } -} - -public abstract class BaseSampleClass -{ - public int Calculate() - { - return 0; - } - - public abstract int Calculate(int a, int b); - - public abstract int Calculate(int a, int b, int c); -} - -public class SampleClass : BaseSampleClass -{ - - public override int Calculate(int a, int b) => 0; - - public sealed override int Calculate(int a, int b, int c) => 0; - - public virtual int DoSth() => 0; - - public int Property { get; set; } -} - -internal class MyUnitTests -{ - private void TestOkForAbstractMethod() - { - var mock = new Mock(); - mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); - } - - private void TestOkForOverrideAbstractMethod() - { - var mock = new Mock(); - mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); - } - - private void TestOkForInterfaceMethod() - { - var mock = new Mock(); - mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); - } - - private void TestOkForInterfaceProperty() - { - var mock = new Mock(); - mock.Setup(x => x.TestProperty); - } - - private void TestOkForVirtualMethod() - { - var mock = new Mock(); - mock.Setup(x => x.DoSth()); - } - - private void TestBadSetupForNonVirtualMethod() - { - var mock = new Mock(); - mock.Setup(x => x.Calculate()); - } - - private void TestBadSetupForSealedMethod() - { - var mock = new Mock(); - mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny(), It.IsAny())); - } - - private void TestBadSetupForNonVirtualProperty() - { - var mock = new Mock(); - mock.Setup(x => x.Property); - } -} diff --git a/Source/Moq.Analyzers.Test/Data/SetupShouldNotIncludeAsyncResult.cs b/Source/Moq.Analyzers.Test/Data/SetupShouldNotIncludeAsyncResult.cs deleted file mode 100644 index fbb903f34..000000000 --- a/Source/Moq.Analyzers.Test/Data/SetupShouldNotIncludeAsyncResult.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; -using Moq; - -#pragma warning disable SA1402 // File may only contain a single class -#pragma warning disable SA1649 // File name must match first type name -#pragma warning disable SA1502 // Element must not be on a single line - -namespace SetupShouldNotIncludeAsyncResult; - -public class AsyncClient -{ - public virtual Task VoidAsync() => Task.CompletedTask; - public virtual Task GenericAsyncWithConcreteReturn() => Task.FromResult(string.Empty); -} - -internal class MyUnitTests -{ - private void TestOkForTask() - { - var mock = new Mock(); - mock.Setup(c => c.VoidAsync()); - } - - private void TestOkForTaskWithConcreteReturn() - { - var mock = new Mock(); - mock.Setup(c => c.GenericAsyncWithConcreteReturn().Result); - } - - private void TestOkForTaskWithConcreteReturnProperSetup() - { - var mock = new Mock(); - mock.Setup(c => c.GenericAsyncWithConcreteReturn()) - .ReturnsAsync(string.Empty); - } -} diff --git a/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj b/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj index 4e1ba91be..b4e3a49df 100644 --- a/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj +++ b/Source/Moq.Analyzers.Test/Moq.Analyzers.Test.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -41,40 +41,5 @@ - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - \ No newline at end of file diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasConstructorParameters.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasConstructorParameters.verified.txt new file mode 100644 index 000000000..8822aefe0 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasConstructorParameters.verified.txt @@ -0,0 +1,32 @@ +Diagnostic 1 + Id: Moq1001 + Location: SourceFile(Test0.cs[231..241)) + Highlight: (25, true) + Lines: var mock1 = new Mock(25, true); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 2 + Id: Moq1001 + Location: SourceFile(Test0.cs[283..290)) + Highlight: ("123") + Lines: var mock2 = new Mock("123"); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 3 + Id: Moq1001 + Location: SourceFile(Test0.cs[332..342)) + Highlight: (25, true) + Lines: var mock3 = new Mock(25, true); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 4 + Id: Moq1001 + Location: SourceFile(Test0.cs[384..391)) + Highlight: ("123") + Lines: var mock4 = new Mock("123"); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasConstructorParametersAndExplicitMockBehavior.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasConstructorParametersAndExplicitMockBehavior.verified.txt new file mode 100644 index 000000000..3501f8d28 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasConstructorParametersAndExplicitMockBehavior.verified.txt @@ -0,0 +1,32 @@ +Diagnostic 1 + Id: Moq1001 + Location: SourceFile(Test0.cs[263..292)) + Highlight: (MockBehavior.Default, "123") + Lines: var mock1 = new Mock(MockBehavior.Default, "123"); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 2 + Id: Moq1001 + Location: SourceFile(Test0.cs[334..365)) + Highlight: (MockBehavior.Strict, 25, true) + Lines: var mock2 = new Mock(MockBehavior.Strict, 25, true); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 3 + Id: Moq1001 + Location: SourceFile(Test0.cs[407..436)) + Highlight: (MockBehavior.Default, "123") + Lines: var mock3 = new Mock(MockBehavior.Default, "123"); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 4 + Id: Moq1001 + Location: SourceFile(Test0.cs[478..508)) + Highlight: (MockBehavior.Loose, 25, true) + Lines: var mock4 = new Mock(MockBehavior.Loose, 25, true); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasParameters.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasParameters.verified.txt deleted file mode 100644 index db89c8868..000000000 --- a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIfMockedInterfaceHasParameters.verified.txt +++ /dev/null @@ -1,64 +0,0 @@ -Diagnostic 1 - Id: Moq1001 - Location: SourceFile(Test0.cs[794..804)) - Highlight: (25, true) - Lines: var mock1 = new Moq.Mock(25, true); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 2 - Id: Moq1001 - Location: SourceFile(Test0.cs[846..853)) - Highlight: ("123") - Lines: var mock2 = new Mock("123"); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 3 - Id: Moq1001 - Location: SourceFile(Test0.cs[936..946)) - Highlight: (25, true) - Lines: var mock3 = new Mock(25, true); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 4 - Id: Moq1001 - Location: SourceFile(Test0.cs[1033..1040)) - Highlight: ("123") - Lines: var mock4 = new Moq.Mock("123"); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 5 - Id: Moq1001 - Location: SourceFile(Test0.cs[1127..1160)) - Highlight: (Moq.MockBehavior.Default, "123") - Lines: var mock1 = new Moq.Mock(Moq.MockBehavior.Default, "123"); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 6 - Id: Moq1001 - Location: SourceFile(Test0.cs[1202..1233)) - Highlight: (MockBehavior.Strict, 25, true) - Lines: var mock2 = new Mock(MockBehavior.Strict, 25, true); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 7 - Id: Moq1001 - Location: SourceFile(Test0.cs[1316..1349)) - Highlight: (Moq.MockBehavior.Default, "123") - Lines: var mock3 = new Mock(Moq.MockBehavior.Default, "123"); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 8 - Id: Moq1001 - Location: SourceFile(Test0.cs[1436..1466)) - Highlight: (MockBehavior.Loose, 25, true) - Lines: var mock4 = new Moq.Mock(MockBehavior.Loose, 25, true); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIsRealMoqIsUsedWithInvalidParameters.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIsRealMoqIsUsedWithInvalidParameters.verified.txt new file mode 100644 index 000000000..efa763351 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldFailIsRealMoqIsUsedWithInvalidParameters.verified.txt @@ -0,0 +1,48 @@ +Diagnostic 1 + Id: Moq1001 + Location: SourceFile(Test0.cs[550..559)) + Highlight: (1, true) + Lines: var mock1 = new Moq.Mock(1, true); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 2 + Id: Moq1001 + Location: SourceFile(Test0.cs[605..610)) + Highlight: ("2") + Lines: var mock2 = new Moq.Mock("2"); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 3 + Id: Moq1001 + Location: SourceFile(Test0.cs[656..687)) + Highlight: (Moq.MockBehavior.Default, "3") + Lines: var mock3 = new Moq.Mock(Moq.MockBehavior.Default, "3"); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 4 + Id: Moq1001 + Location: SourceFile(Test0.cs[733..762)) + Highlight: (MockBehavior.Loose, 4, true) + Lines: var mock4 = new Moq.Mock(MockBehavior.Loose, 4, true); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 5 + Id: Moq1001 + Location: SourceFile(Test0.cs[808..830)) + Highlight: (MockBehavior.Default) + Lines: var mock5 = new Moq.Mock(MockBehavior.Default); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + +Diagnostic 6 + Id: Moq1001 + Location: SourceFile(Test0.cs[876..898)) + Highlight: (MockBehavior.Default) + Lines: var mock6 = new Moq.Mock(MockBehavior.Default); + Severity: Warning + Message: Mocked interfaces cannot have constructor parameters. + diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt index 657c227be..d39fa8d42 100644 --- a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfCustomMockClassIsUsed.verified.txt @@ -1,48 +1 @@ -Diagnostic 1 - Id: Moq1001 - Location: SourceFile(Test0.cs[1088..1097)) - Highlight: (1, true) - Lines: var mock1 = new Moq.Mock(1, true); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 2 - Id: Moq1001 - Location: SourceFile(Test0.cs[1184..1189)) - Highlight: ("2") - Lines: var mock2 = new Moq.Mock("2"); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 3 - Id: Moq1001 - Location: SourceFile(Test0.cs[1235..1266)) - Highlight: (Moq.MockBehavior.Default, "3") - Lines: var mock3 = new Moq.Mock(Moq.MockBehavior.Default, "3"); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 4 - Id: Moq1001 - Location: SourceFile(Test0.cs[1353..1382)) - Highlight: (MockBehavior.Loose, 4, true) - Lines: var mock4 = new Moq.Mock(MockBehavior.Loose, 4, true); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 5 - Id: Moq1001 - Location: SourceFile(Test0.cs[1428..1450)) - Highlight: (MockBehavior.Default) - Lines: var mock5 = new Moq.Mock(MockBehavior.Default); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - -Diagnostic 6 - Id: Moq1001 - Location: SourceFile(Test0.cs[1537..1559)) - Highlight: (MockBehavior.Default) - Lines: var mock6 = new Moq.Mock(MockBehavior.Default); - Severity: Warning - Message: Mocked interfaces cannot have constructor parameters. - +emptyString diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfMockedInterfaceDoesNotHaveConstructorParameters.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfMockedInterfaceDoesNotHaveConstructorParameters.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfMockedInterfaceDoesNotHaveConstructorParameters.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfRealMoqIsUsedWithValidParameters.verified.txt b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfRealMoqIsUsedWithValidParameters.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.ShouldPassIfRealMoqIsUsedWithValidParameters.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs index c72b969d8..947198bdc 100644 --- a/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/NoConstructorArgumentsForInterfaceMockAnalyzerTests.cs @@ -9,15 +9,232 @@ namespace Moq.Analyzers.Test; public class NoConstructorArgumentsForInterfaceMockAnalyzerTests : DiagnosticVerifier { [Fact] - public Task ShouldFailIfMockedInterfaceHasParameters() + public Task ShouldFailIfMockedInterfaceHasConstructorParameters() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoConstructorArgumentsForInterfaceMock_1.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace NoConstructorArgumentsForInterfaceMock.TestBad; + + internal interface IMyService + { + void Do(string s); + } + + internal class MyUnitTests + { + private void TestBad() + { + var mock1 = new Mock(25, true); + var mock2 = new Mock("123"); + var mock3 = new Mock(25, true); + var mock4 = new Mock("123"); + } + } + """ + ])); + } + + [Fact] + public Task ShouldFailIfMockedInterfaceHasConstructorParametersAndExplicitMockBehavior() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace NoConstructorArgumentsForInterfaceMock.TestBadWithMockBehavior; + + internal interface IMyService + { + void Do(string s); + } + + internal class MyUnitTests + { + private void TestBadWithMockBehavior() + { + var mock1 = new Mock(MockBehavior.Default, "123"); + var mock2 = new Mock(MockBehavior.Strict, 25, true); + var mock3 = new Mock(MockBehavior.Default, "123"); + var mock4 = new Mock(MockBehavior.Loose, 25, true); + } + } + """ + ])); } + [Fact] + public Task ShouldPassIfMockedInterfaceDoesNotHaveConstructorParameters() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace NoConstructorArgumentsForInterfaceMock.TestGood; + + internal interface IMyService + { + void Do(string s); + } + + internal class MyUnitTests + { + private void TestGood() + { + var mock1 = new Mock(); + var mock2 = new Mock(MockBehavior.Default); + var mock3 = new Mock(MockBehavior.Strict); + var mock4 = new Mock(MockBehavior.Loose); + } + } + """ + ])); + } + + // TODO: This feels like it should be in every analyzer's tests [Fact] public Task ShouldPassIfCustomMockClassIsUsed() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoConstructorArgumentsForInterfaceMock_2.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace NoConstructorArgumentsForInterfaceMock.TestFakeMoq; + + public enum MockBehavior + { + Default, + Strict, + Loose, + } + + internal interface IMyService + { + void Do(string s); + } + + public class Mock + where T : class + { + public Mock() { } + + public Mock(params object[] ar) { } + + public Mock(MockBehavior behavior) { } + + public Mock(MockBehavior behavior, params object[] args) { } + } + + internal class MyUnitTests + { + private void TestFakeMoq() + { + var mock1 = new Mock("4"); + var mock2 = new Mock(5, true); + var mock3 = new Mock(MockBehavior.Strict, 6, true); + var mock4 = new Mock(Moq.MockBehavior.Default, "5"); + var mock5 = new Mock(MockBehavior.Strict); + var mock6 = new Mock(MockBehavior.Loose); + } + } + """ + ])); + } + + // TODO: This feels duplicated with other tests + [Fact] + public Task ShouldFailIsRealMoqIsUsedWithInvalidParameters() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace NoConstructorArgumentsForInterfaceMock.TestRealMoqWithBadParameters; + + public enum MockBehavior + { + Default, + Strict, + Loose, + } + + internal interface IMyService + { + void Do(string s); + } + + public class Mock + where T : class + { + public Mock() { } + + public Mock(params object[] ar) { } + + public Mock(MockBehavior behavior) { } + + public Mock(MockBehavior behavior, params object[] args) { } + } + + internal class MyUnitTests + { + private void TestRealMoqWithBadParameters() + { + var mock1 = new Moq.Mock(1, true); + var mock2 = new Moq.Mock("2"); + var mock3 = new Moq.Mock(Moq.MockBehavior.Default, "3"); + var mock4 = new Moq.Mock(MockBehavior.Loose, 4, true); + var mock5 = new Moq.Mock(MockBehavior.Default); + var mock6 = new Moq.Mock(MockBehavior.Default); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassIfRealMoqIsUsedWithValidParameters() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + namespace NoConstructorArgumentsForInterfaceMock.TestRealMoqWithGoodParameters; + + public enum MockBehavior + { + Default, + Strict, + Loose, + } + + internal interface IMyService + { + void Do(string s); + } + + public class Mock + where T : class + { + public Mock() { } + + public Mock(params object[] ar) { } + + public Mock(MockBehavior behavior) { } + + public Mock(MockBehavior behavior, params object[] args) { } + } + + internal class MyUnitTests + { + private void TestRealMoqWithGoodParameters() + { + var mock1 = new Moq.Mock(Moq.MockBehavior.Default); + var mock2 = new Moq.Mock(Moq.MockBehavior.Default); + } + } + """ + ])); } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() diff --git a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.Test.verified.txt b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.ShouldFailWhenMethodsUsePropertySetup.verified.txt similarity index 81% rename from Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.Test.verified.txt rename to Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.ShouldFailWhenMethodsUsePropertySetup.verified.txt index d5f86c56b..03718f921 100644 --- a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.Test.verified.txt +++ b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.ShouldFailWhenMethodsUsePropertySetup.verified.txt @@ -1,6 +1,6 @@ Diagnostic 1 Id: Moq1101 - Location: SourceFile(Test0.cs[872..882)) + Location: SourceFile(Test0.cs[311..321)) Highlight: x.Method() Lines: mock.SetupGet(x => x.Method()); Severity: Warning @@ -8,7 +8,7 @@ Diagnostic 2 Id: Moq1101 - Location: SourceFile(Test0.cs[912..922)) + Location: SourceFile(Test0.cs[351..361)) Highlight: x.Method() Lines: mock.SetupSet(x => x.Method()); Severity: Warning diff --git a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.ShouldPassWhenPropertiesUsePropertySetup.verified.txt b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.ShouldPassWhenPropertiesUsePropertySetup.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.ShouldPassWhenPropertiesUsePropertySetup.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs index c6cdfccee..ec2e96a97 100644 --- a/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/NoMethodsInPropertySetupAnalyzerTests.cs @@ -9,11 +9,77 @@ namespace Moq.Analyzers.Test; public class NoMethodsInPropertySetupAnalyzerTests : DiagnosticVerifier { [Fact] - public Task Test() + public Task ShouldPassWhenPropertiesUsePropertySetup() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoMethodsInPropertySetup.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace NoMethodsInPropertySetup.Good; + + public interface IFoo + { + string Prop1 { get; set; } + + string Prop2 { get; } + + string Prop3 { set; } + + string Method(); + } + + public class MyUnitTests + { + private void TestGood() + { + var mock = new Mock(); + mock.SetupGet(x => x.Prop1); + mock.SetupGet(x => x.Prop2); + mock.SetupSet(x => x.Prop1 = "1"); + mock.SetupSet(x => x.Prop3 = "2"); + mock.Setup(x => x.Method()); + } + } + """ + ])); } + [Fact] + public Task ShouldFailWhenMethodsUsePropertySetup() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace NoMethodsInPropertySetup.Bad; + + public interface IFoo + { + string Prop1 { get; set; } + + string Prop2 { get; } + + string Prop3 { set; } + + string Method(); + } + + public class MyUnitTests + { + private void TestBad() + { + var mock = new Mock(); + mock.SetupGet(x => x.Method()); + mock.SetupSet(x => x.Method()); + } + } + """ + ])); + } + + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() { return new NoMethodsInPropertySetupAnalyzer(); diff --git a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailIfFileIsSealed.verified.txt b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailIfFileIsSealed.verified.txt deleted file mode 100644 index b9435c141..000000000 --- a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailIfFileIsSealed.verified.txt +++ /dev/null @@ -1,32 +0,0 @@ -Diagnostic 1 - Id: Moq1000 - Location: SourceFile(Test0.cs[785..794)) - Highlight: FooSealed - Lines: var mock1 = new Moq.Mock(); - Severity: Warning - Message: Sealed classes cannot be mocked. - -Diagnostic 2 - Id: Moq1000 - Location: SourceFile(Test0.cs[828..837)) - Highlight: FooSealed - Lines: var mock2 = new Mock(); - Severity: Warning - Message: Sealed classes cannot be mocked. - -Diagnostic 3 - Id: Moq1000 - Location: SourceFile(Test0.cs[871..899)) - Highlight: NoSealedClassMocks.FooSealed - Lines: var mock3 = new Mock(); - Severity: Warning - Message: Sealed classes cannot be mocked. - -Diagnostic 4 - Id: Moq1000 - Location: SourceFile(Test0.cs[937..965)) - Highlight: NoSealedClassMocks.FooSealed - Lines: var mock4 = new Moq.Mock(); - Severity: Warning - Message: Sealed classes cannot be mocked. - diff --git a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailWhenClassIsSealed.verified.txt b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailWhenClassIsSealed.verified.txt new file mode 100644 index 000000000..8712e81a5 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldFailWhenClassIsSealed.verified.txt @@ -0,0 +1,8 @@ +Diagnostic 1 + Id: Moq1000 + Location: SourceFile(Test0.cs[214..223)) + Highlight: FooSealed + Lines: var mock = new Mock(); + Severity: Warning + Message: Sealed classes cannot be mocked. + diff --git a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldPassWhenClassIsNotSealed.verified.txt b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldPassWhenClassIsNotSealed.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.ShouldPassWhenClassIsNotSealed.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs index d09e25cb9..748fcf8eb 100644 --- a/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/NoSealedClassMocksAnalyzerTests.cs @@ -9,9 +9,55 @@ namespace Moq.Analyzers.Test; public class NoSealedClassMocksAnalyzerTests : DiagnosticVerifier { [Fact] - public Task ShouldFailIfFileIsSealed() + public Task ShouldFailWhenClassIsSealed() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/NoSealedClassMocks.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System; + using Moq; + + namespace NoSealedClassMocks.Sealed; + + internal sealed class FooSealed { } + + internal class Foo { } + + internal class MyUnitTests + { + private void Sealed() + { + var mock = new Mock(); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenClassIsNotSealed() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System; + using Moq; + + namespace NoSealedClassMocks.NotSealed; + + internal sealed class FooSealed { } + + internal class Foo { } + + internal class MyUnitTests + { + private void NotSealed() + { + var mock = new Mock(); + } + } + """ + ])); } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithANonVirtualMethod.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithANonVirtualMethod.verified.txt new file mode 100644 index 000000000..11477c42b --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithANonVirtualMethod.verified.txt @@ -0,0 +1,8 @@ +Diagnostic 1 + Id: Moq1200 + Location: SourceFile(Test0.cs[428..441)) + Highlight: x.Calculate() + Lines: mock.Setup(x => x.Calculate()); + Severity: Error + Message: Setup should be used only for overridable members. + diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithANonVirtualProperty.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithANonVirtualProperty.verified.txt new file mode 100644 index 000000000..82663df6c --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithANonVirtualProperty.verified.txt @@ -0,0 +1,8 @@ +Diagnostic 1 + Id: Moq1200 + Location: SourceFile(Test0.cs[314..324)) + Highlight: x.Property + Lines: mock.Setup(x => x.Property); + Severity: Error + Message: Setup should be used only for overridable members. + diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithASealedMethod.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithASealedMethod.verified.txt new file mode 100644 index 000000000..7beb85849 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldFailWhenSetupIsCalledWithASealedMethod.verified.txt @@ -0,0 +1,8 @@ +Diagnostic 1 + Id: Moq1200 + Location: SourceFile(Test0.cs[588..650)) + Highlight: x.Calculate(It.IsAny(), It.IsAny(), It.IsAny()) + Lines: mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny(), It.IsAny())); + Severity: Error + Message: Setup should be used only for overridable members. + diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassIfGoodParameters.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassIfGoodParameters.verified.txt deleted file mode 100644 index 1a68dc7ad..000000000 --- a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassIfGoodParameters.verified.txt +++ /dev/null @@ -1,24 +0,0 @@ -Diagnostic 1 - Id: Moq1200 - Location: SourceFile(Test0.cs[1852..1865)) - Highlight: x.Calculate() - Lines: mock.Setup(x => x.Calculate()); - Severity: Error - Message: Setup should be used only for overridable members. - -Diagnostic 2 - Id: Moq1200 - Location: SourceFile(Test0.cs[1996..2058)) - Highlight: x.Calculate(It.IsAny(), It.IsAny(), It.IsAny()) - Lines: mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny(), It.IsAny())); - Severity: Error - Message: Setup should be used only for overridable members. - -Diagnostic 3 - Id: Moq1200 - Location: SourceFile(Test0.cs[2195..2205)) - Highlight: x.Property - Lines: mock.Setup(x => x.Property); - Severity: Error - Message: Setup should be used only for overridable members. - diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAVirtualMethod.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAVirtualMethod.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAVirtualMethod.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnAbstractMethod.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnAbstractMethod.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnAbstractMethod.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnInterfaceMethod.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnInterfaceMethod.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnInterfaceMethod.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnInterfaceProperty.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnInterfaceProperty.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnInterfaceProperty.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnOverrideOfAnAbstractMethod.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnOverrideOfAnAbstractMethod.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.ShouldPassWhenSetupIsCalledWithAnOverrideOfAnAbstractMethod.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs index 7edac2b29..2503d7e1b 100644 --- a/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests.cs @@ -9,9 +9,252 @@ namespace Moq.Analyzers.Test; public class SetupShouldBeUsedOnlyForOverridableMembersAnalyzerTests : DiagnosticVerifier { [Fact] - public Task ShouldPassIfGoodParameters() + public Task ShouldFailWhenSetupIsCalledWithANonVirtualMethod() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/SetupOnlyForOverridableMembers.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestBadSetupForNonVirtualMethod; + + public abstract class BaseSampleClass + { + public int Calculate() => 0; + + public abstract int Calculate(int a, int b); + + public abstract int Calculate(int a, int b, int c); + } + + internal class MyUnitTests + { + private void TestBadSetupForNonVirtualMethod() + { + var mock = new Mock(); + mock.Setup(x => x.Calculate()); + } + } + """ + ])); + } + + [Fact] + public Task ShouldFailWhenSetupIsCalledWithANonVirtualProperty() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestBadSetupForNonVirtualProperty; + + public class SampleClass + { + + public int Property { get; set; } + } + + internal class MyUnitTests + { + private void TestBadSetupForNonVirtualProperty() + { + var mock = new Mock(); + mock.Setup(x => x.Property); + } + } + """ + ])); + } + + [Fact] + public Task ShouldFailWhenSetupIsCalledWithASealedMethod() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestBadSetupForSealedMethod; + + public abstract class BaseSampleClass + { + public int Calculate() => 0; + + public abstract int Calculate(int a, int b); + + public abstract int Calculate(int a, int b, int c); + } + + public class SampleClass : BaseSampleClass + { + + public override int Calculate(int a, int b) => 0; + + public sealed override int Calculate(int a, int b, int c) => 0; + } + + internal class MyUnitTests + { + private void TestBadSetupForSealedMethod() + { + var mock = new Mock(); + mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny(), It.IsAny())); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenSetupIsCalledWithAnAbstractMethod() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestOkForAbstractMethod; + + public abstract class BaseSampleClass + { + public int Calculate() => 0; + + public abstract int Calculate(int a, int b); + + public abstract int Calculate(int a, int b, int c); + } + + internal class MyUnitTests + { + private void TestOkForAbstractMethod() + { + var mock = new Mock(); + mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenSetupIsCalledWithAnInterfaceMethod() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestOkForInterfaceMethod; + + public interface ISampleInterface + { + int Calculate(int a, int b); + } + + internal class MyUnitTests + { + private void TestOkForInterfaceMethod() + { + var mock = new Mock(); + mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenSetupIsCalledWithAnInterfaceProperty() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestOkForInterfaceProperty; + + public interface ISampleInterface + { + int TestProperty { get; set; } + } + + internal class MyUnitTests + { + private void TestOkForInterfaceProperty() + { + var mock = new Mock(); + mock.Setup(x => x.TestProperty); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenSetupIsCalledWithAnOverrideOfAnAbstractMethod() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestOkForOverrideAbstractMethod; + + public abstract class BaseSampleClass + { + public int Calculate() => 0; + + public abstract int Calculate(int a, int b); + + public abstract int Calculate(int a, int b, int c); + } + + public class SampleClass : BaseSampleClass + { + + public override int Calculate(int a, int b) => 0; + + public sealed override int Calculate(int a, int b, int c) => 0; + } + + internal class MyUnitTests + { + private void TestOkForOverrideAbstractMethod() + { + var mock = new Mock(); + mock.Setup(x => x.Calculate(It.IsAny(), It.IsAny())); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenSetupIsCalledWithAVirtualMethod() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using Moq; + + namespace SetupOnlyForOverridableMembers.TestOkForVirtualMethod; + + public class SampleClass + { + public virtual int DoSth() => 0; + } + + internal class MyUnitTests + { + private void TestOkForVirtualMethod() + { + var mock = new Mock(); + mock.Setup(x => x.DoSth()); + } + } + """ + ])); } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() diff --git a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldFailWhenSetupWithTaskResult.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldFailWhenSetupWithTaskResult.verified.txt new file mode 100644 index 000000000..57c69be0e --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldFailWhenSetupWithTaskResult.verified.txt @@ -0,0 +1,8 @@ +Diagnostic 1 + Id: Moq1201 + Location: SourceFile(Test0.cs[428..455)) + Highlight: c.GenericTaskAsync().Result + Lines: mock.Setup(c => c.GenericTaskAsync().Result); + Severity: Error + Message: Setup of async methods should use ReturnsAsync instead of .Result + diff --git a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassIfSetupProperly.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassIfSetupProperly.verified.txt deleted file mode 100644 index 8b863fb7d..000000000 --- a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassIfSetupProperly.verified.txt +++ /dev/null @@ -1,8 +0,0 @@ -Diagnostic 1 - Id: Moq1201 - Location: SourceFile(Test0.cs[773..814)) - Highlight: c.GenericAsyncWithConcreteReturn().Result - Lines: mock.Setup(c => c.GenericAsyncWithConcreteReturn().Result); - Severity: Error - Message: Setup of async methods should use ReturnsAsync instead of .Result - diff --git a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassWhenSetupWithReturnsAsync.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassWhenSetupWithReturnsAsync.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassWhenSetupWithReturnsAsync.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassWhenSetupWithoutReturn.verified.txt b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassWhenSetupWithoutReturn.verified.txt new file mode 100644 index 000000000..d39fa8d42 --- /dev/null +++ b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.ShouldPassWhenSetupWithoutReturn.verified.txt @@ -0,0 +1 @@ +emptyString diff --git a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs index 58b07741d..47819bc8f 100644 --- a/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs +++ b/Source/Moq.Analyzers.Test/SetupShouldNotIncludeAsyncResultAnalyzerTests.cs @@ -9,9 +9,94 @@ namespace Moq.Analyzers.Test; public class SetupShouldNotIncludeAsyncResultAnalyzerTests : DiagnosticVerifier { [Fact] - public Task ShouldPassIfSetupProperly() + public Task ShouldPassWhenSetupWithoutReturn() { - return Verify(VerifyCSharpDiagnostic(File.ReadAllText("Data/SetupShouldNotIncludeAsyncResult.cs"))); + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System.Threading.Tasks; + using Moq; + + namespace SetupShouldNotIncludeAsyncResult.TestOkForTask; + + public class AsyncClient + { + public virtual Task TaskAsync() => Task.CompletedTask; + + public virtual Task GenericTaskAsync() => Task.FromResult(string.Empty); + } + + internal class MyUnitTests + { + private void TestOkForTask() + { + var mock = new Mock(); + mock.Setup(c => c.TaskAsync()); + } + } + """ + ])); + } + + [Fact] + public Task ShouldPassWhenSetupWithReturnsAsync() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System.Threading.Tasks; + using Moq; + + namespace SetupShouldNotIncludeAsyncResult.TestOkForGenericTaskProperSetup; + + public class AsyncClient + { + public virtual Task TaskAsync() => Task.CompletedTask; + + public virtual Task GenericTaskAsync() => Task.FromResult(string.Empty); + } + + internal class MyUnitTests + { + private void TestOkForGenericTaskProperSetup() + { + var mock = new Mock(); + mock.Setup(c => c.GenericTaskAsync()) + .ReturnsAsync(string.Empty); + } + } + """ + ])); + } + + [Fact] + public Task ShouldFailWhenSetupWithTaskResult() + { + return Verify(VerifyCSharpDiagnostic( + [ + """ + using System.Threading.Tasks; + using Moq; + + namespace SetupShouldNotIncludeAsyncResult.TestBadForGenericTask; + + public class AsyncClient + { + public virtual Task TaskAsync() => Task.CompletedTask; + + public virtual Task GenericTaskAsync() => Task.FromResult(string.Empty); + } + + internal class MyUnitTests + { + private void TestBadForGenericTask() + { + var mock = new Mock(); + mock.Setup(c => c.GenericTaskAsync().Result); + } + } + """ + ])); } protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()