From 1e0e828a6ad08d0e6f7d91e48ce7f00a77b39317 Mon Sep 17 00:00:00 2001 From: mclift Date: Sat, 11 Mar 2017 18:02:01 +0000 Subject: [PATCH] Add support for custom delegate-based events --- .../CodeGen/EventStubber.cs | 67 ++++++++++++++----- .../Utils/StubbingUtils.cs | 3 - test/TestClassLibrary/ITestInterface.cs | 7 ++ test/TestClassLibraryTest/EventStubsTest.cs | 28 +++++++- 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/src/SimpleStubs.CodeGen/CodeGen/EventStubber.cs b/src/SimpleStubs.CodeGen/CodeGen/EventStubber.cs index a696d81..e828947 100644 --- a/src/SimpleStubs.CodeGen/CodeGen/EventStubber.cs +++ b/src/SimpleStubs.CodeGen/CodeGen/EventStubber.cs @@ -28,17 +28,31 @@ namespace Etg.SimpleStubs.CodeGen classDclr = classDclr.AddMembers(eventDclr); string eventName = eventSymbol.Name; - ParameterSyntax[] parameters = GetEventParameters(eventSymbol); - string onEventArgs = "sender"; - string eventTriggerArgs = "sender"; - if (parameters.Count() == 2) + + bool isCustomDelegateEvent = IsCustomDelegateBasedEvent(eventSymbol, semanticModel); + ParameterSyntax[] parameters = GetEventParameters(eventSymbol, isCustomDelegateEvent); + string onEventArgs; + string eventTriggerArgs; + + if (isCustomDelegateEvent) { - onEventArgs += ", args"; - eventTriggerArgs += ", args"; + IMethodSymbol delegateInvokeMethodSymbol = ((INamedTypeSymbol)(eventSymbol.OriginalDefinition).Type).DelegateInvokeMethod; + onEventArgs = StubbingUtils.FormatParameters(delegateInvokeMethodSymbol); + eventTriggerArgs = onEventArgs; } - else if (parameters.Count() == 1) + else { - onEventArgs += ", null"; + onEventArgs = "sender"; + eventTriggerArgs = "sender"; + if (parameters.Count() == 2) + { + onEventArgs += ", args"; + eventTriggerArgs += ", args"; + } + else if (parameters.Count() == 1) + { + onEventArgs += ", null"; + } } string eventType = GetEventType(eventSymbol); @@ -69,17 +83,25 @@ namespace Etg.SimpleStubs.CodeGen return classDclr; } - private static ParameterSyntax[] GetEventParameters(IEventSymbol eventSymbol) + private static ParameterSyntax[] GetEventParameters(IEventSymbol eventSymbol, bool isCustomDelegateEvent) { - List parameters = new List - { - SF.Parameter(SF.Identifier("sender")).WithType(SF.ParseTypeName("object")) - }; + + var parameters = new List(); INamedTypeSymbol type = (INamedTypeSymbol) (eventSymbol.Type); - if (type.TypeArguments.Any()) + + if (isCustomDelegateEvent) { - parameters.Add(SF.Parameter(SF.Identifier("args")) - .WithType(SF.ParseTypeName(type.TypeArguments[0].Name))); + IMethodSymbol delegateInvokeMethodSymbol = ((INamedTypeSymbol)(eventSymbol.OriginalDefinition).Type).DelegateInvokeMethod; + parameters.AddRange(RoslynUtils.GetMethodParameterSyntaxList(delegateInvokeMethodSymbol).ToArray()); + } + else + { + parameters.Add(SF.Parameter(SF.Identifier("sender")).WithType(SF.ParseTypeName("object"))); + if (type.TypeArguments.Any()) + { + parameters.Add(SF.Parameter(SF.Identifier("args")) + .WithType(SF.ParseTypeName(type.TypeArguments[0].Name))); + } } return parameters.ToArray(); @@ -100,5 +122,18 @@ namespace Etg.SimpleStubs.CodeGen { return eventSymbol.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); } + + private static bool IsCustomDelegateBasedEvent(IEventSymbol eventSymbol, SemanticModel semanticModel) + { + var genericEventType = semanticModel.Compilation.GetTypeByMetadataName("System.EventHandler`1"); + var eventType = semanticModel.Compilation.GetTypeByMetadataName("System.EventHandler"); + + if (eventSymbol.Type.MetadataName.Equals(genericEventType.MetadataName) || eventSymbol.Type.MetadataName.Equals(eventType.MetadataName)) + { + return false; + } + + return true; + } } } \ No newline at end of file diff --git a/src/SimpleStubs.CodeGen/Utils/StubbingUtils.cs b/src/SimpleStubs.CodeGen/Utils/StubbingUtils.cs index 5ace192..ae9c9ce 100644 --- a/src/SimpleStubs.CodeGen/Utils/StubbingUtils.cs +++ b/src/SimpleStubs.CodeGen/Utils/StubbingUtils.cs @@ -1,11 +1,8 @@ using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.MSBuild; namespace Etg.SimpleStubs.CodeGen.Utils { diff --git a/test/TestClassLibrary/ITestInterface.cs b/test/TestClassLibrary/ITestInterface.cs index 566eb9a..cf1ac6f 100644 --- a/test/TestClassLibrary/ITestInterface.cs +++ b/test/TestClassLibrary/ITestInterface.cs @@ -113,4 +113,11 @@ namespace TestClassLibrary void SetBoo(T t, A a) where T : class, IDisposable, new() where A : new(); } + + public delegate void CustomDelegateBasedHandler(int arg1, string arg2, object arg3); + + public interface ICustomDelegateBasedEventExample + { + event CustomDelegateBasedHandler CustomDelegateEventOccurred; + } } \ No newline at end of file diff --git a/test/TestClassLibraryTest/EventStubsTest.cs b/test/TestClassLibraryTest/EventStubsTest.cs index 4fde613..f69b65c 100644 --- a/test/TestClassLibraryTest/EventStubsTest.cs +++ b/test/TestClassLibraryTest/EventStubsTest.cs @@ -1,4 +1,5 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; using TestClassLibrary; namespace TestClassLibraryTest @@ -16,11 +17,32 @@ namespace TestClassLibraryTest { sender = s; newNumber = num; - } - ; + }; + stub.PhoneNumberChanged_Raise(this, 55); Assert.AreEqual(55, newNumber); Assert.AreEqual(this, sender); } + + [TestMethod] + public void TestCustomDelegateBasedEventStub() + { + int arg1 = 0; + string arg2 = null; + object arg3 = null; + var stub = new StubICustomDelegateBasedEventExample(); + stub.CustomDelegateEventOccurred += (i, s, o) => + { + arg1 = i; + arg2 = s; + arg3 = o; + }; + + stub.CustomDelegateEventOccurred_Raise(55, "test", new Random(1)); + + Assert.AreEqual(55, arg1); + Assert.AreEqual("test", arg2); + Assert.AreEqual(typeof(Random), arg3.GetType()); + } } }