diff --git a/Source/Mockolate.SourceGenerators/Entities/MockClass.cs b/Source/Mockolate.SourceGenerators/Entities/MockClass.cs index 497cd788..54aca608 100644 --- a/Source/Mockolate.SourceGenerators/Entities/MockClass.cs +++ b/Source/Mockolate.SourceGenerators/Entities/MockClass.cs @@ -33,13 +33,4 @@ public MockClass(ITypeSymbol[] types) : base(types[0]) public IEnumerable DistinctAdditionalImplementations() => AdditionalImplementations.Distinct().Where(x => x.ClassFullName != ClassFullName); - - internal IEnumerable GetAllClasses() - { - yield return this; - foreach (Class implementation in DistinctAdditionalImplementations()) - { - yield return implementation; - } - } } diff --git a/Source/Mockolate.SourceGenerators/MockGenerator.cs b/Source/Mockolate.SourceGenerators/MockGenerator.cs index 78e431b0..e702c5a5 100644 --- a/Source/Mockolate.SourceGenerators/MockGenerator.cs +++ b/Source/Mockolate.SourceGenerators/MockGenerator.cs @@ -54,7 +54,7 @@ private static void Execute(ImmutableArray mocksToGenerate, SourcePro { context.AddSource($"MockFor{mockToGenerate.Name}Extensions.g.cs", SourceText.From( - Sources.Sources.ForMockCombinationExtensions(mockToGenerate.Name, mockToGenerate.MockClass), + Sources.Sources.ForMockCombinationExtensions(mockToGenerate.Name, mockToGenerate.MockClass, mockToGenerate.MockClass.DistinctAdditionalImplementations()), Encoding.UTF8)); } } diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.CombinationExtensions.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.CombinationExtensions.cs index c31e365f..f1ca1a9f 100644 --- a/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.CombinationExtensions.cs +++ b/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.CombinationExtensions.cs @@ -1,14 +1,13 @@ using System.Text; -using Microsoft.CodeAnalysis; using Mockolate.SourceGenerators.Entities; -using Type = Mockolate.SourceGenerators.Entities.Type; namespace Mockolate.SourceGenerators.Sources; #pragma warning disable S3776 // Cognitive Complexity of methods should not be too high internal static partial class Sources { - public static string ForMockCombinationExtensions(string name, MockClass mockClass) + public static string ForMockCombinationExtensions(string name, MockClass mockClass, + IEnumerable distinctAdditionalImplementations) { StringBuilder sb = InitializeBuilder([ "Mockolate.Exceptions", @@ -56,282 +55,69 @@ private static Mock GetMockOrThrow(T subject) """); sb.AppendLine(); - if (mockClass.Delegate is not null) + sb.Append("\textension(").Append(mockClass.ClassFullName).AppendLine(" subject)"); + sb.AppendLine("\t{"); + + HashSet usedNames = []; + foreach (Class @class in distinctAdditionalImplementations) { - AppendDelegateExtensions(sb, mockClass, mockClass.Delegate); + AppendAdditionalMockExtensions(sb, @class, usedNames); } - else - { - if (mockClass.AdditionalImplementations.Any()) - { - AppendMockExtensions(sb, mockClass); - } - sb.AppendLine(); - } + sb.AppendLine("\t}"); sb.AppendLine("}"); sb.AppendLine("#nullable disable"); return sb.ToString(); } - private static void AppendDelegateExtensions(StringBuilder sb, MockClass mockClass, Method method) + private static void AppendAdditionalMockExtensions(StringBuilder sb, Class @class, HashSet usedNames) { - #region Setup - - sb.Append("\textension(IMockSetup<").Append(mockClass.ClassFullName).AppendLine("> setup)"); - sb.AppendLine("\t{"); - sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\t/// Sets up the delegate on the mock.").AppendLine(); - sb.Append("\t\t/// ").AppendLine(); - if (method.ReturnType != Type.Void) - { - sb.Append("\t\tpublic ReturnMethodSetup<") - .Append(method.ReturnType.Fullname); - foreach (MethodParameter parameter in method.Parameters) - { - sb.Append(", ").Append(parameter.Type.Fullname); - } - - sb.Append("> Delegate("); - } - else - { - sb.Append("\t\tpublic VoidMethodSetup"); - if (method.Parameters.Count > 0) - { - sb.Append('<'); - int index = 0; - foreach (MethodParameter parameter in method.Parameters) - { - if (index++ > 0) - { - sb.Append(", "); - } - - sb.Append(parameter.Type.Fullname); - } - - sb.Append('>'); - } - - sb.Append(" Delegate("); - } - - int i = 0; - foreach (MethodParameter parameter in method.Parameters) - { - if (i++ > 0) - { - sb.Append(", "); - } - - sb.Append(parameter.RefKind switch - { - RefKind.Ref => "IRefParameter<", - RefKind.Out => "IOutParameter<", - _ => "IParameter<", - }).Append(parameter.Type.Fullname) - .Append('>'); - if (parameter.RefKind is not RefKind.Ref and not RefKind.Out) - { - sb.Append('?'); - } - - sb.Append(' ').Append(parameter.Name); - } - - sb.Append(")"); - if (method.GenericParameters is not null && method.GenericParameters.Value.Count > 0) - { - foreach (GenericParameter gp in method.GenericParameters.Value) - { - gp.AppendWhereConstraint(sb, "\t\t\t"); - } - } - sb.AppendLine(); - - sb.AppendLine("\t\t{"); - - if (method.ReturnType != Type.Void) + int nameSuffix = 1; + string name = @class.ClassName.Replace('.', '_'); + while (!usedNames.Add(name)) { - sb.Append("\t\t\tvar methodSetup = new ReturnMethodSetup<") - .Append(method.ReturnType.Fullname); - foreach (MethodParameter parameter in method.Parameters) - { - sb.Append(", ").Append(parameter.Type.Fullname); - } - - sb.Append(">"); - } - else - { - sb.Append("\t\t\tvar methodSetup = new VoidMethodSetup"); - - if (method.Parameters.Count > 0) - { - sb.Append('<'); - int index = 0; - foreach (MethodParameter parameter in method.Parameters) - { - if (index++ > 0) - { - sb.Append(", "); - } - - sb.Append(parameter.Type.Fullname); - } - - sb.Append('>'); - } - } - - sb.Append("(\"").Append(mockClass.ClassFullName).Append('.').Append(method.Name).Append("\""); - foreach (MethodParameter parameter in method.Parameters) - { - sb.Append(", new NamedParameter(\"").Append(parameter.Name).Append("\", ").Append(parameter.Name); - if (parameter.RefKind is not RefKind.Ref and not RefKind.Out) - { - sb.Append(" ?? It.IsNull<").Append(parameter.Type.Fullname) - .Append(">()"); - } - - sb.Append(")"); + name = $"{@class.ClassName.Replace('.', '_')}__{++nameSuffix}"; } - sb.Append(");").AppendLine(); - sb.AppendLine("\t\t\tif (setup is IMockSetup mockSetup)"); - sb.AppendLine("\t\t\t{"); - sb.AppendLine("\t\t\t\tmockSetup.RegisterMethod(methodSetup);"); - sb.AppendLine("\t\t\t}"); - sb.AppendLine("\t\t\treturn methodSetup;"); - sb.AppendLine("\t\t}"); - sb.AppendLine("\t}"); - - #endregion - - sb.AppendLine(); - - #region Verify - - sb.Append("\textension(IMockVerify<").Append(mockClass.ClassFullName).Append(", Mock<") - .Append(mockClass.ClassFullName).Append(">>").Append(" verify)").AppendLine(); - sb.AppendLine("\t{"); sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\t/// Verifies the delegate invocations for on the mock.").AppendLine(); + sb.Append("\t\t/// Sets up the mock for ") + .AppendLine(); sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\tpublic VerificationResult<").Append(mockClass.ClassFullName).Append("> Invoked("); - i = 0; - foreach (MethodParameter parameter in method.Parameters) + sb.Append("\t\tpublic IMockSetup<").Append(@class.ClassFullName).Append("> Setup").Append(name) + .Append("Mock") + .AppendLine(); + sb.Append("\t\t\t=> new Mock<").Append(@class.ClassFullName).Append(">((").Append(@class.ClassFullName) + .Append(")subject, GetMockOrThrow(subject).Registrations);") + .AppendLine(); + if (@class.AllEvents().Any()) { - if (i++ > 0) - { - sb.Append(", "); - } - - sb.Append(parameter.RefKind switch - { - RefKind.Ref => "IVerifyRefParameter<", - RefKind.Out => "IVerifyOutParameter<", - _ => "IParameter<", - }).Append(parameter.Type.Fullname) - .Append('>'); - if (parameter.RefKind is not RefKind.Ref and not RefKind.Out) - { - sb.Append('?'); - } - - sb.Append(' ').Append(parameter.Name); - } - - sb.Append(")").AppendLine(); - sb.Append("\t\t{").AppendLine(); - sb.Append("\t\t\tIMockInvoked>> invoked = (IMockInvoked>>)verify;").AppendLine(); - sb.Append("\t\t\treturn invoked.Method(\"") - .Append(mockClass.ClassFullName).Append('.').Append(method.Name) - .Append("\""); - - foreach (MethodParameter parameter in method.Parameters) - { - sb.Append(", "); - sb.Append(parameter.Name); - if (parameter.RefKind is not RefKind.Ref and not RefKind.Out) - { - sb.Append(" ?? It.IsNull<").Append(parameter.Type.Fullname) - .Append(">()"); - } - } - - sb.AppendLine(");"); - sb.Append("\t\t}").AppendLine(); - - sb.AppendLine("\t}"); - - #endregion - } - - private static void AppendMockExtensions(StringBuilder sb, MockClass mockClass) - { - sb.Append("\textension(").Append(mockClass.ClassFullName).AppendLine(" subject)"); - sb.AppendLine("\t{"); - - HashSet usedNames = []; - foreach (Class? @class in mockClass.DistinctAdditionalImplementations()) - { - sb.AppendLine(); - int nameSuffix = 1; - string name = @class.ClassName.Replace('.', '_'); - while (!usedNames.Add(name)) - { - name = $"{@class.ClassName.Replace('.', '_')}__{++nameSuffix}"; - } - - sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\t/// Sets up the mock for ") - .AppendLine(); - sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\tpublic IMockSetup<").Append(@class.ClassFullName).Append("> Setup").Append(name) - .Append("Mock") - .AppendLine(); - sb.Append("\t\t\t=> new Mock<").Append(@class.ClassFullName).Append(">((").Append(@class.ClassFullName) - .Append(")subject, GetMockOrThrow(subject).Registrations);") - .AppendLine(); - if (@class.AllEvents().Any()) - { - sb.AppendLine(); - sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\t/// Raise events on the mock for ").AppendLine(); - sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\tpublic IMockRaises<").Append(@class.ClassFullName).Append("> RaiseOn") - .Append(name).Append("Mock").AppendLine(); - sb.Append("\t\t\t=> new Mock<").Append(@class.ClassFullName).Append(">((").Append(@class.ClassFullName) - .Append(")subject, GetMockOrThrow(subject).Registrations);") - .AppendLine(); - } - sb.AppendLine(); sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\t/// Verifies the interactions with the mocked subject of on the mock.").AppendLine(); + sb.Append("\t\t/// Raise events on the mock for ").AppendLine(); sb.Append("\t\t/// ").AppendLine(); - sb.Append("\t\tpublic IMockVerify<").Append(@class.ClassFullName).Append("> VerifyOn").Append(name) - .Append("Mock") - .AppendLine(); + sb.Append("\t\tpublic IMockRaises<").Append(@class.ClassFullName).Append("> RaiseOn") + .Append(name).Append("Mock").AppendLine(); sb.Append("\t\t\t=> new Mock<").Append(@class.ClassFullName).Append(">((").Append(@class.ClassFullName) .Append(")subject, GetMockOrThrow(subject).Registrations);") .AppendLine(); } - sb.AppendLine("\t}"); + sb.AppendLine(); + sb.Append("\t\t/// ").AppendLine(); + sb.Append("\t\t/// Verifies the interactions with the mocked subject of on the mock.").AppendLine(); + sb.Append("\t\t/// ").AppendLine(); + sb.Append("\t\tpublic IMockVerify<").Append(@class.ClassFullName).Append("> VerifyOn").Append(name) + .Append("Mock") + .AppendLine(); + sb.Append("\t\t\t=> new Mock<").Append(@class.ClassFullName).Append(">((").Append(@class.ClassFullName) + .Append(")subject, GetMockOrThrow(subject).Registrations);") + .AppendLine(); } } #pragma warning restore S3776 // Cognitive Complexity of methods should not be too high diff --git a/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.cs b/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.cs index 0141c33a..48ab6e7e 100644 --- a/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.cs +++ b/Source/Mockolate.SourceGenerators/Sources/Sources.ForMock.cs @@ -26,13 +26,7 @@ namespace Mockolate.Generated; sb.Append("/// ").AppendLine(); sb.Append("/// A mock implementing "); - foreach (Class? additional in mockClass.DistinctAdditionalImplementations()) - { - sb.Append(" and "); - } - - sb.AppendLine("."); + .Append("\" />."); sb.Append("/// ").AppendLine(); sb.Append("internal class MockFor").Append(name).Append(" : IMockSubject<").Append(mockClass.ClassFullName) .Append(">").AppendLine(); diff --git a/Tests/Mockolate.SourceGenerators.Tests/Sources/ForMockTests.ImplementClassTests.cs b/Tests/Mockolate.SourceGenerators.Tests/Sources/ForMockTests.ImplementClassTests.cs index 2ffb283a..f01d0ae1 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Sources/ForMockTests.ImplementClassTests.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Sources/ForMockTests.ImplementClassTests.cs @@ -4,6 +4,44 @@ public sealed partial class ForMockTests { public sealed class ImplementClassTests { + [Fact] + public async Task BaseClassMethodWithParameterNamedBaseResult_ShouldGenerateUniqueLocalVariableName() + { + GeneratorResult result = Generator + .Run(""" + using Mockolate; + + namespace MyCode; + + public class Program + { + public static void Main(string[] args) + { + _ = Mock.Create(); + } + } + + public class MyService + { + public virtual int ProcessData(int baseResult) => baseResult; + } + """); + + await That(result.Sources).ContainsKey("MockForMyService.g.cs").WhoseValue + .Contains("MethodSetupResult methodExecution = MockRegistrations.InvokeMethod(") + .IgnoringNewlineStyle().And + .Contains("if (methodExecution.CallBaseClass)") + .IgnoringNewlineStyle().And + .Contains("var baseResult1 = base.ProcessData(baseResult);") + .IgnoringNewlineStyle().And + .Contains("return methodExecution.GetResult(baseResult1);") + .Or + .Contains("if (!methodExecution.HasSetupResult)") + .IgnoringNewlineStyle().And + .Contains("return baseResult1;") + .IgnoringNewlineStyle(); + } + [Fact] public async Task Events_MultipleImplementations_ShouldOnlyHaveOneExplicitImplementation() { @@ -264,6 +302,7 @@ public class MyService { public virtual event EventHandler SomeEvent; public event EventHandler? SomeOtherEvent; + protected virtual event EventHandler SomeProtectedEvent; } public interface IMyOtherService @@ -475,6 +514,101 @@ int MyCode.IMyOtherService.this[string someAdditionalIndex] """).IgnoringNewlineStyle(); } + [Fact] + public async Task InterfaceIndexerWithParameterNamedIndexerResult_ShouldGenerateUniqueLocalVariableName() + { + GeneratorResult result = Generator + .Run(""" + using Mockolate; + + namespace MyCode; + + public class Program + { + public static void Main(string[] args) + { + _ = Mock.Create(); + } + } + + public interface IMyService + { + int this[int indexerResult] { get; set; } + } + """); + + await That(result.Sources).ContainsKey("MockForIMyService.g.cs").WhoseValue + .Contains( + "return MockRegistrations.GetIndexer(indexerResult).GetResult(() => MockRegistrations.Behavior.DefaultValue.Generate(default(int)!));") + .IgnoringNewlineStyle().And + .Contains("MockRegistrations.SetIndexer(value, indexerResult);") + .IgnoringNewlineStyle(); + } + + [Fact] + public async Task InterfaceMethodWithParameterNamedMethodExecution_ShouldGenerateUniqueLocalVariableName() + { + GeneratorResult result = Generator + .Run(""" + using Mockolate; + + namespace MyCode; + + public class Program + { + public static void Main(string[] args) + { + _ = Mock.Create(); + } + } + + public interface IMyService + { + int ProcessData(int methodExecution); + } + """); + + await That(result.Sources).ContainsKey("MockForIMyService.g.cs").WhoseValue + .Contains("MethodSetupResult methodExecution1 = MockRegistrations.InvokeMethod(") + .IgnoringNewlineStyle().And + .Contains("methodExecution1.TriggerCallbacks(methodExecution)") + .IgnoringNewlineStyle().And + .Contains("return methodExecution1.Result;") + .IgnoringNewlineStyle(); + } + + [Fact] + public async Task InterfaceMethodWithParameterNamedResult_ShouldGenerateUniqueLocalVariableName() + { + GeneratorResult result = Generator + .Run(""" + using Mockolate; + + namespace MyCode; + + public class Program + { + public static void Main(string[] args) + { + _ = Mock.Create(); + } + } + + public interface IMyService + { + int ProcessResult(int result); + } + """); + + await That(result.Sources).ContainsKey("MockForIMyService.g.cs").WhoseValue + .Contains("MethodSetupResult methodExecution = MockRegistrations.InvokeMethod(") + .IgnoringNewlineStyle().And + .Contains("methodExecution.TriggerCallbacks(result)") + .IgnoringNewlineStyle().And + .Contains("return methodExecution.Result;") + .IgnoringNewlineStyle(); + } + [Theory] [InlineData("class, T")] [InlineData("struct")] @@ -802,8 +936,14 @@ public static void Main(string[] args) public class MyService { - public virtual void MyMethod1(int index); - protected virtual bool MyMethod2(int index, bool isReadOnly); + public virtual void MyMethod1(int index, ref int value1, out bool flag) + { + flag = true; + } + protected virtual bool MyMethod2(int index, bool isReadOnly, ref int value1, out bool flag) + { + flag = true; + } public void MyNonVirtualMethod(); } @@ -815,32 +955,54 @@ public interface IMyOtherService await That(result.Sources).ContainsKey("MockForMyService_IMyOtherService.g.cs").WhoseValue .Contains(""" - public override void MyMethod1(int index) + /// + public override void MyMethod1(int index, ref int value1, out bool flag) { - MethodSetupResult methodExecution = MockRegistrations.InvokeMethod("MyCode.MyService.MyMethod1", index); + MethodSetupResult methodExecution = MockRegistrations.InvokeMethod("MyCode.MyService.MyMethod1", index, value1, null); if (methodExecution.CallBaseClass) { - base.MyMethod1(index); + base.MyMethod1(index, ref value1, out flag); } - methodExecution.TriggerCallbacks(index); + methodExecution.TriggerCallbacks(index, value1, flag); + + value1 = methodExecution.SetRefParameter("value1", value1); + methodExecution.TriggerCallbacks(index, value1, flag); + + flag = methodExecution.SetOutParameter("flag", () => MockRegistrations.Behavior.DefaultValue.Generate(default(bool)!)); + methodExecution.TriggerCallbacks(index, value1, flag); } """).IgnoringNewlineStyle().And .Contains(""" - /// - protected override bool MyMethod2(int index, bool isReadOnly) + /// + protected override bool MyMethod2(int index, bool isReadOnly, ref int value1, out bool flag) { - MethodSetupResult methodExecution = MockRegistrations.InvokeMethod("MyCode.MyService.MyMethod2", p => MockRegistrations.Behavior.DefaultValue.Generate(default(bool)!, p), index, isReadOnly); + MethodSetupResult methodExecution = MockRegistrations.InvokeMethod("MyCode.MyService.MyMethod2", p => MockRegistrations.Behavior.DefaultValue.Generate(default(bool)!, p), index, isReadOnly, value1, null); if (methodExecution.CallBaseClass) { - var baseResult = base.MyMethod2(index, isReadOnly); + var baseResult = base.MyMethod2(index, isReadOnly, ref value1, out flag); + if (methodExecution.HasSetupResult == true) + { + value1 = methodExecution.SetRefParameter("value1", value1); + } + + if (methodExecution.HasSetupResult == true) + { + flag = methodExecution.SetOutParameter("flag", () => MockRegistrations.Behavior.DefaultValue.Generate(default(bool)!)); + } + if (!methodExecution.HasSetupResult) { - methodExecution.TriggerCallbacks(index, isReadOnly); + methodExecution.TriggerCallbacks(index, isReadOnly, value1, flag); return baseResult; } } + else + { + value1 = methodExecution.SetRefParameter("value1", value1); + flag = methodExecution.SetOutParameter("flag", () => MockRegistrations.Behavior.DefaultValue.Generate(default(bool)!)); + } - methodExecution.TriggerCallbacks(index, isReadOnly); + methodExecution.TriggerCallbacks(index, isReadOnly, value1, flag); return methodExecution.Result; } """).IgnoringNewlineStyle().And @@ -893,7 +1055,7 @@ public void MyMethod1(ref int index) { index = methodExecution.SetRefParameter("index", index); } - + } index = methodExecution.SetRefParameter("index", index); methodExecution.TriggerCallbacks(index); @@ -911,7 +1073,7 @@ public bool MyMethod2(int index, out bool isReadOnly) { isReadOnly = methodExecution.SetOutParameter("isReadOnly", () => MockRegistrations.Behavior.DefaultValue.Generate(default(bool)!)); } - + if (!methodExecution.HasSetupResult) { methodExecution.TriggerCallbacks(index, isReadOnly); @@ -925,6 +1087,57 @@ public bool MyMethod2(int index, out bool isReadOnly) """).IgnoringNewlineStyle(); } + [Fact] + public async Task Methods_ShouldSupportSpanParameters() + { + GeneratorResult result = Generator + .Run(""" + using System; + using Mockolate; + + namespace MyCode; + public class Program + { + public static void Main(string[] args) + { + _ = Mock.Create(); + } + } + + public interface IMyService + { + void MyMethod1(Span buffer); + bool MyMethod2(ReadOnlySpan values); + } + """); + + await That(result.Sources).ContainsKey("MockForIMyServiceExtensions.g.cs").WhoseValue + .Contains(""" + public IVoidMethodSetup> MyMethod1(ISpanParameter buffer) + { + var methodSetup = new VoidMethodSetup>("MyCode.IMyService.MyMethod1", new NamedParameter("buffer", (IParameter)(buffer))); + CastToMockRegistrationOrThrow(setup).SetupMethod(methodSetup); + return methodSetup; + } + """).IgnoringNewlineStyle().And + .Contains(""" + public IReturnMethodSetup> MyMethod2(IReadOnlySpanParameter values) + { + var methodSetup = new ReturnMethodSetup>("MyCode.IMyService.MyMethod2", new NamedParameter("values", (IParameter)(values))); + CastToMockRegistrationOrThrow(setup).SetupMethod(methodSetup); + return methodSetup; + } + """).IgnoringNewlineStyle().And + .Contains(""" + public VerificationResult MyMethod1(IVerifySpanParameter buffer) + => CastToMockOrThrow(verifyInvoked).Method("MyCode.IMyService.MyMethod1", new NamedParameter("buffer", (IParameter)(buffer))); + """).IgnoringNewlineStyle().And + .Contains(""" + public VerificationResult MyMethod2(IVerifyReadOnlySpanParameter values) + => CastToMockOrThrow(verifyInvoked).Method("MyCode.IMyService.MyMethod2", new NamedParameter("values", (IParameter)(values))); + """).IgnoringNewlineStyle(); + } + [Fact] public async Task Properties_MultipleImplementations_ShouldOnlyHaveOneExplicitImplementation() { @@ -1254,137 +1467,5 @@ int MyCode.IMyOtherService.SomeAdditionalProperty } """).IgnoringNewlineStyle(); } - - [Fact] - public async Task InterfaceMethodWithParameterNamedMethodExecution_ShouldGenerateUniqueLocalVariableName() - { - GeneratorResult result = Generator - .Run(""" - using Mockolate; - - namespace MyCode; - - public class Program - { - public static void Main(string[] args) - { - _ = Mock.Create(); - } - } - - public interface IMyService - { - int ProcessData(int methodExecution); - } - """); - - await That(result.Sources).ContainsKey("MockForIMyService.g.cs").WhoseValue - .Contains("MethodSetupResult methodExecution1 = MockRegistrations.InvokeMethod(") - .IgnoringNewlineStyle().And - .Contains("methodExecution1.TriggerCallbacks(methodExecution)") - .IgnoringNewlineStyle().And - .Contains("return methodExecution1.Result;") - .IgnoringNewlineStyle(); - } - - [Fact] - public async Task InterfaceMethodWithParameterNamedResult_ShouldGenerateUniqueLocalVariableName() - { - GeneratorResult result = Generator - .Run(""" - using Mockolate; - - namespace MyCode; - - public class Program - { - public static void Main(string[] args) - { - _ = Mock.Create(); - } - } - - public interface IMyService - { - int ProcessResult(int result); - } - """); - - await That(result.Sources).ContainsKey("MockForIMyService.g.cs").WhoseValue - .Contains("MethodSetupResult methodExecution = MockRegistrations.InvokeMethod(") - .IgnoringNewlineStyle().And - .Contains("methodExecution.TriggerCallbacks(result)") - .IgnoringNewlineStyle().And - .Contains("return methodExecution.Result;") - .IgnoringNewlineStyle(); - } - - [Fact] - public async Task InterfaceIndexerWithParameterNamedIndexerResult_ShouldGenerateUniqueLocalVariableName() - { - GeneratorResult result = Generator - .Run(""" - using Mockolate; - - namespace MyCode; - - public class Program - { - public static void Main(string[] args) - { - _ = Mock.Create(); - } - } - - public interface IMyService - { - int this[int indexerResult] { get; set; } - } - """); - - await That(result.Sources).ContainsKey("MockForIMyService.g.cs").WhoseValue - .Contains("return MockRegistrations.GetIndexer(indexerResult).GetResult(() => MockRegistrations.Behavior.DefaultValue.Generate(default(int)!));") - .IgnoringNewlineStyle().And - .Contains("MockRegistrations.SetIndexer(value, indexerResult);") - .IgnoringNewlineStyle(); - } - - [Fact] - public async Task BaseClassMethodWithParameterNamedBaseResult_ShouldGenerateUniqueLocalVariableName() - { - GeneratorResult result = Generator - .Run(""" - using Mockolate; - - namespace MyCode; - - public class Program - { - public static void Main(string[] args) - { - _ = Mock.Create(); - } - } - - public class MyService - { - public virtual int ProcessData(int baseResult) => baseResult; - } - """); - - await That(result.Sources).ContainsKey("MockForMyService.g.cs").WhoseValue - .Contains("MethodSetupResult methodExecution = MockRegistrations.InvokeMethod(") - .IgnoringNewlineStyle().And - .Contains("if (methodExecution.CallBaseClass)") - .IgnoringNewlineStyle().And - .Contains("var baseResult1 = base.ProcessData(baseResult);") - .IgnoringNewlineStyle().And - .Contains("return methodExecution.GetResult(baseResult1);") - .Or - .Contains("if (!methodExecution.HasSetupResult)") - .IgnoringNewlineStyle().And - .Contains("return baseResult1;") - .IgnoringNewlineStyle(); - } } } diff --git a/Tests/Mockolate.SourceGenerators.Tests/Sources/MockClassTests.cs b/Tests/Mockolate.SourceGenerators.Tests/Sources/MockClassTests.cs index 6e2095b1..0069e84b 100644 --- a/Tests/Mockolate.SourceGenerators.Tests/Sources/MockClassTests.cs +++ b/Tests/Mockolate.SourceGenerators.Tests/Sources/MockClassTests.cs @@ -38,4 +38,41 @@ await That(source) $"public static T Create(BaseClass.ConstructorParameters constructorParameters, MockBehavior mockBehavior, params Action>[] setups)"); } } + + [Fact] + public async Task ShouldSupportSpecialTypes() + { + GeneratorResult result = Generator + .Run(""" + using System; + using Mockolate; + + namespace MyCode; + public class Program + { + public static void Main(string[] args) + { + _ = Mock.Create(); + } + } + + public interface IMyService + { + void MyMethod(object v1, bool v2, string v3, char v4, byte v5, sbyte v6, short v7, ushort v8, int v9, uint v10, long v11, ulong v12, float v13, double v14, decimal v15); + } + """); + + await That(result.Sources).ContainsKey("MockForIMyService.g.cs").WhoseValue + .Contains(""" + public void MyMethod(object v1, bool v2, string v3, char v4, byte v5, sbyte v6, short v7, ushort v8, int v9, uint v10, long v11, ulong v12, float v13, double v14, decimal v15) + { + MethodSetupResult methodExecution = MockRegistrations.InvokeMethod("MyCode.IMyService.MyMethod", v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); + if (this._wrapped is not null) + { + this._wrapped.MyMethod(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); + } + methodExecution.TriggerCallbacks(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); + } + """).IgnoringNewlineStyle(); + } }