-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #131 from ColmBhandal/feature/pre-access-wrapper
Feature/pre access wrapper
- Loading branch information
Showing
7 changed files
with
245 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
|
||
namespace CsharpExtras.Event.Wrapper | ||
{ | ||
/// <summary> | ||
/// Encapsulates access to some object, so that accessing that object is always preceded by a pre-access action | ||
/// </summary> | ||
/// <typeparam name="TObj"></typeparam> | ||
public interface IPreAccessWrapper<TObj> | ||
{ | ||
/// <summary> | ||
/// Gets the result of applying some function to the object | ||
/// </summary> | ||
/// <typeparam name="TReturn">The return type of the function</typeparam> | ||
/// <param name="f">The function to apply</param> | ||
/// <returns>The result of the function</returns> | ||
TReturn Get<TReturn>(Func<TObj, TReturn> f); | ||
|
||
/// <summary> | ||
/// Runs the given action on the object | ||
/// </summary> | ||
/// <param name="act">The action to run on the object</param> | ||
void Run(Action<TObj> act); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace CsharpExtras.Event.Wrapper | ||
{ | ||
internal class PreAccessWrapperImpl<TObj> : IPreAccessWrapper<TObj> | ||
{ | ||
private readonly TObj _object; | ||
private readonly Action<TObj> _preAccessAction; | ||
|
||
public PreAccessWrapperImpl(TObj obj, Action<TObj> preAccessAction) | ||
{ | ||
_object = obj; | ||
_preAccessAction = preAccessAction ?? throw new ArgumentNullException(nameof(preAccessAction)); | ||
} | ||
|
||
public void Run(Action<TObj> act) | ||
{ | ||
_preAccessAction(_object); | ||
act(_object); | ||
} | ||
|
||
public TReturn Get<TReturn>(Func<TObj, TReturn> f) | ||
{ | ||
_preAccessAction(_object); | ||
return f(_object); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
using CsharpExtras.Api; | ||
using CsharpExtras.Event.Wrapper; | ||
using Moq; | ||
using NUnit.Framework; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace CsharpExtrasTest.Event.Wrapper | ||
{ | ||
[TestFixture, Category("Unit")] | ||
internal class PreAccessWrapperTest | ||
{ | ||
private ICsharpExtrasApi Api { get; } = new CsharpExtrasApi(); | ||
|
||
[Test] | ||
public void GIVEN_Wrapper_WHEN_Get_THEN_ExpectedValueReturned() | ||
{ | ||
//Arrange | ||
Mock<IEventHandler> mockHandler = new Mock<IEventHandler>(); | ||
Mock<ITestObj> mockObj = new Mock<ITestObj>(); | ||
Mock<ITestObj> mockOtherObj = new Mock<ITestObj>(); | ||
Action<ITestObj> preAccessAction = o => mockHandler.Object.Handle(o); | ||
Mock<ITestGetter<ITestObj>> mockGetter = new Mock<ITestGetter<ITestObj>>(); | ||
|
||
mockHandler.Setup(x => x.Handle(It.IsAny<ITestObj>())); | ||
mockGetter.Setup(g => g.Get(mockObj.Object)).Returns(mockOtherObj.Object); | ||
|
||
IPreAccessWrapper<ITestObj> wrapper | ||
= Api.NewPreAccessWrapper(mockObj.Object, preAccessAction); | ||
|
||
//Act | ||
ITestObj obj = wrapper.Get(mockGetter.Object.Get); | ||
|
||
//Assert | ||
Assert.AreSame(mockOtherObj.Object, obj); | ||
} | ||
|
||
[Test] | ||
public void GIVEN_Wrapper_WHEN_Get_THEN_AllOperationsRunInExpectedOrder() | ||
{ | ||
//Arrange | ||
Mock<IEventHandler> mockHandler = new Mock<IEventHandler>(); | ||
Mock<ITestObj> mockObj = new Mock<ITestObj>(); | ||
Mock<ITestObj> mockOtherObj = new Mock<ITestObj>(); | ||
Action<ITestObj> preAccessAction = o => mockHandler.Object.Handle(o); | ||
Mock<ITestGetter<ITestObj>> mockGetter = new Mock<ITestGetter<ITestObj>>(); | ||
|
||
|
||
//Used to verify order of operations. See: https://stackoverflow.com/a/10609506/5134722 | ||
int callOrder = 0; | ||
mockHandler.Setup(x => x.Handle(It.IsAny<ITestObj>())) | ||
.Callback(() => Assert.AreEqual(0, callOrder++)).Verifiable(); | ||
mockGetter.Setup(g => g.Get(mockObj.Object)).Returns(mockOtherObj.Object) | ||
.Callback(() => Assert.AreEqual(1, callOrder++)).Verifiable(); | ||
|
||
IPreAccessWrapper<ITestObj> wrapper | ||
= Api.NewPreAccessWrapper(mockObj.Object, preAccessAction); | ||
|
||
//Act | ||
wrapper.Get(mockGetter.Object.Get); | ||
|
||
//Assert | ||
mockObj.Verify(); | ||
mockHandler.Verify(); | ||
} | ||
|
||
[Test] | ||
public void GIVEN_Wrapper_WHEN_Run_THEN_AllOperationsRunInExpectedOrder() | ||
{ | ||
//Arrange | ||
Mock<IEventHandler> mockHandler = new Mock<IEventHandler>(); | ||
Mock<ITestObj> mockObj = new Mock<ITestObj>(); | ||
Action<ITestObj> preAccessAction = o => mockHandler.Object.Handle(o); | ||
|
||
|
||
//Used to verify order of operations. See: https://stackoverflow.com/a/10609506/5134722 | ||
int callOrder = 0; | ||
mockHandler.Setup(x => x.Handle(It.IsAny<ITestObj>())) | ||
.Callback(() => Assert.AreEqual(0, callOrder++)).Verifiable(); | ||
mockObj.Setup(o => o.Foo()) | ||
.Callback(() => Assert.AreEqual(1, callOrder++)).Verifiable(); | ||
|
||
IPreAccessWrapper<ITestObj> wrapper | ||
= Api.NewPreAccessWrapper(mockObj.Object, preAccessAction); | ||
|
||
//Act | ||
wrapper.Run(o => o.Foo()); | ||
|
||
//Assert | ||
mockObj.Verify(); | ||
mockHandler.Verify(); | ||
} | ||
|
||
[Test] | ||
public void GIVEN_PreAccessException_WHEN_Run_THEN_ExceptionThrownAndActionNotExecuted() | ||
{ | ||
//Arrange | ||
Mock<IEventHandler> mockHandler = new Mock<IEventHandler>(); | ||
Mock<ITestObj> mockObj = new Mock<ITestObj>(); | ||
Action<ITestObj> preAccessAction = o => mockHandler.Object.Handle(o); | ||
|
||
mockHandler.Setup(x => x.Handle(It.IsAny<ITestObj>())) | ||
.Throws<ArgumentException>(); | ||
mockObj.Setup(o => o.Foo()).Verifiable(); | ||
|
||
IPreAccessWrapper<ITestObj> wrapper | ||
= Api.NewPreAccessWrapper(mockObj.Object, preAccessAction); | ||
|
||
//Act | ||
Assert.Throws<ArgumentException>(() => wrapper.Run(o => o.Foo())); | ||
|
||
//Assert | ||
mockObj.Verify(o => o.Foo(), Times.Never()); | ||
} | ||
|
||
[Test] | ||
public void GIVEN_PreAccessException_WHEN_Get_THEN_ExceptionThrownAndGetNotExecuted() | ||
{ | ||
//Arrange | ||
Mock<IEventHandler> mockHandler = new Mock<IEventHandler>(); | ||
Mock<ITestObj> mockObj = new Mock<ITestObj>(); | ||
Mock<ITestObj> mockOtherObj = new Mock<ITestObj>(); | ||
Action<ITestObj> preAccessAction = o => mockHandler.Object.Handle(o); | ||
Mock<ITestGetter<ITestObj>> mockGetter = new Mock<ITestGetter<ITestObj>>(); | ||
|
||
mockHandler.Setup(x => x.Handle(It.IsAny<ITestObj>())) | ||
.Throws<ArgumentException>(); | ||
mockGetter.Setup(g => g.Get(mockObj.Object)).Returns(mockOtherObj.Object) | ||
.Verifiable(); | ||
|
||
IPreAccessWrapper<ITestObj> wrapper | ||
= Api.NewPreAccessWrapper(mockObj.Object, preAccessAction); | ||
|
||
//Act | ||
Assert.Throws<ArgumentException>(() => wrapper.Get(mockGetter.Object.Get)); | ||
|
||
//Assert | ||
mockGetter.Verify(g => g.Get(It.IsAny<ITestObj>()), Times.Never()); | ||
} | ||
} | ||
|
||
interface ITestGetter<TResult> | ||
{ | ||
TResult Get(ITestObj obj); | ||
} | ||
|
||
interface ITestObj | ||
{ | ||
void Foo(); | ||
} | ||
|
||
interface IEventHandler | ||
{ | ||
void Handle(ITestObj obj); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
// In SDK-style projects such as this one, several assembly attributes that were historically | ||
// defined in this file are now automatically added during build and populated with | ||
// values defined in project properties. For details of which attributes are included | ||
// and how to customise this process see: https://aka.ms/assembly-info-properties | ||
|
||
|
||
// Setting ComVisible to false makes the types in this assembly not visible to COM | ||
// components. If you need to access a type in this assembly from COM, set the ComVisible | ||
// attribute to true on that type. | ||
|
||
[assembly: ComVisible(false)] | ||
|
||
// The following GUID is for the ID of the typelib if this project is exposed to COM. | ||
|
||
[assembly: Guid("7909326e-9e35-48ed-9e25-4b74d183b0a0")] | ||
|
||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] |