Skip to content

Commit

Permalink
Updated event raising logic to only allow internal default constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
Mihnea Rădulescu committed May 28, 2024
1 parent ee276f3 commit 4bd429e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 9 deletions.
11 changes: 10 additions & 1 deletion src/NSubstitute/Core/Events/RaiseEventWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ protected EventArgs GetDefaultForEventArgType(Type type)
{
if (type == typeof(EventArgs)) return EventArgs.Empty;

var defaultConstructor = GetPublicDefaultConstructor(type) ?? GetNonPublicDefaultConstructor(type);
var defaultConstructor = GetPublicDefaultConstructor(type) ?? GetInternalDefaultConstructor(type);
if (defaultConstructor is null)
{
var message = string.Format(
Expand All @@ -24,10 +24,19 @@ protected EventArgs GetDefaultForEventArgType(Type type)
return (EventArgs)defaultConstructor.Invoke([]);
}

private static ConstructorInfo? GetInternalDefaultConstructor(Type type)
{
var nonPublicDefaultConstructor = GetNonPublicDefaultConstructor(type);
var isInternalDefaultConstructor = nonPublicDefaultConstructor?.IsAssembly == true;
return isInternalDefaultConstructor ? nonPublicDefaultConstructor : null;
}

private static ConstructorInfo? GetPublicDefaultConstructor(Type type)
=> GetDefaultConstructor(type, BindingFlags.Public);

private static ConstructorInfo? GetNonPublicDefaultConstructor(Type type)
=> GetDefaultConstructor(type, BindingFlags.NonPublic);

private static ConstructorInfo? GetDefaultConstructor(Type type, BindingFlags bindingFlags)
=> type.GetConstructor(
BindingFlags.Instance | BindingFlags.ExactBinding | bindingFlags, null, Type.EmptyTypes, null);
Expand Down
36 changes: 28 additions & 8 deletions tests/NSubstitute.Acceptance.Specs/EventRaising.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,17 +299,28 @@ public void Raise_custom_event_that_has_sender_and_args_but_does_not_inherit_fro
}

[Test]
public void MyEvent_With_CustomEventArgsWithNonPublicDefaultConstructor_IsRaised()
public void MyEvent_with_CustomEventArgsWithInternalDefaultConstructor_is_raised()
{
// Arrange
IExample mockExample = Substitute.For<IExample>();
var consumer = new Consumer(mockExample);
var exampleInternalMock = Substitute.For<IExampleInternal>();
var consumerInternal = new ConsumerInternal(exampleInternalMock);

// Act
mockExample.MyEvent += Raise.EventWith<CustomEventArgsWithInternalDefaultConstructor>(this, null!);
exampleInternalMock.MyEvent += Raise.EventWith<CustomEventArgsWithInternalDefaultConstructor>(this, null!);

// Assert
Assert.That(consumer.SomethingWasDone);
Assert.That(consumerInternal.SomethingWasDone);
}

[Test]
public void MyEvent_with_CustomEventArgsWithPrivateDefaultConstructor_throws_CannotCreateEventArgsException()
{
// Arrange
var examplePrivateMock = Substitute.For<IExamplePrivate>();

// Act and Assert
Assert.Throws<CannotCreateEventArgsException>(() =>
examplePrivateMock.MyEvent += Raise.EventWith<CustomEventArgsWithPrivateDefaultConstructor>(this, null!));
}

class RaisedEventRecorder<T>
Expand Down Expand Up @@ -358,13 +369,13 @@ public class CustomEventArgsWithInternalDefaultConstructor : EventArgs
{
internal CustomEventArgsWithInternalDefaultConstructor() { }
}
public interface IExample
public interface IExampleInternal
{
public event EventHandler<CustomEventArgsWithInternalDefaultConstructor> MyEvent;
}
public class Consumer
public class ConsumerInternal
{
public Consumer(IExample example)
public ConsumerInternal(IExampleInternal example)
{
example.MyEvent += OnMyEvent;
}
Expand All @@ -378,4 +389,13 @@ private void DoSomething()
SomethingWasDone = true;
}
}

public class CustomEventArgsWithPrivateDefaultConstructor : EventArgs
{
private CustomEventArgsWithPrivateDefaultConstructor() { }
}
public interface IExamplePrivate
{
public event EventHandler<CustomEventArgsWithPrivateDefaultConstructor> MyEvent;
}
}

0 comments on commit 4bd429e

Please sign in to comment.