Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing Moq Wrapper (Take 2) #5699

Open
wants to merge 67 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
4015378
Expose the TypeLibWrapper class for use outside the VBEditor
bclothier Dec 30, 2018
ce5ad8f
Prevent a potential null pointer being returned when the typelib is n…
bclothier Dec 30, 2018
97c3f24
First working version of mocking framework. There are several TODOs a…
bclothier Dec 30, 2018
4048daf
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Dec 30, 2018
6610711
Remove the unfinished file that shouldn't have been included in the c…
bclothier Dec 31, 2018
32e64c1
Handle case where multiple interfaces have same guid.
bclothier Dec 31, 2018
38f055c
Add a provision where a object returned from the Type.GetTypeFromProg…
bclothier Dec 31, 2018
acb96b3
Additional tests
bclothier Dec 31, 2018
c19b7c3
Fix issue with the mocking framework unable to create more than one i…
bclothier Dec 31, 2018
b7a9222
Move RegisteredLibraryFinderService to a TypeLibReflection folder
bclothier Jan 2, 2019
2479094
Refactor our the typelib querying into its own service and update moc…
bclothier Jan 2, 2019
36e3ebb
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Jan 2, 2019
7a1a2d2
Fix typos
bclothier Jan 3, 2019
bcc1873
Fix up the handling of the interfaces in the ComMocked; the mocked ob…
bclothier Jan 3, 2019
0a93417
Refactor the ComMock to perform setups for all members found in all i…
bclothier Jan 3, 2019
2501140
Add caching to the type library query service to avoid non-equivalent…
bclothier Jan 9, 2019
23ba736
Remove unwanted concerns from the provider and also convert its `It` …
bclothier Jan 9, 2019
75863c6
Refactoring of the classes and corrections for ill-formed expressions…
bclothier Jan 9, 2019
b2dc7ff
Need more, more, MORE unit tests! Also get rid of scripting PIA - it'…
bclothier Jan 9, 2019
1edc8d4
Remove a stray using that shouldn't be there.
bclothier Jan 9, 2019
b152adb
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Jan 9, 2019
ba31c13
Make a clean separation of concerns among three issues --- caching of…
bclothier Jan 17, 2019
2624756
Remove unnecessary qualifiers
bclothier Jan 17, 2019
9d0fe50
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Feb 19, 2019
33727c1
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Mar 10, 2019
7ca7567
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Mar 25, 2019
b097952
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Aug 7, 2019
1f75047
Create a class to abstract out the reflection over the Moq.Mock and p…
bclothier Aug 9, 2019
6f15e4b
Fix up the As method as it needs to be closed.
bclothier Aug 9, 2019
89740fd
Integrate the MockReflection into the ComMock to abstract out the ref…
bclothier Aug 11, 2019
ded8618
Modify the callback on the reflection to be consistent with other met…
bclothier Aug 12, 2019
53b4ae3
First version of MockExpressionBuilder to help abstract away the buil…
bclothier Aug 12, 2019
5edfa76
Refactor the mock reflection out of the ComMock, using the builder to…
bclothier Aug 12, 2019
3fe1770
Update Attributions.md
bclothier Aug 14, 2019
fb5a666
Update the void Setup to handle methods that aren't void by delegatin…
bclothier Aug 14, 2019
0a9a540
Move the testing types into their own namespace and add new types for…
bclothier Aug 17, 2019
a10dadd
Introduce VariantConverter class and its accompanying tests. This ena…
bclothier Aug 17, 2019
b921153
Extract the mock argument resolver into its own class and use it inst…
bclothier Aug 17, 2019
ff7df27
Extract the ResolveArgs from ComMock and put them in the resolver. Cr…
bclothier Aug 18, 2019
8a2534a
Rename several classes and their related types away from "Mock" to "S…
bclothier Aug 18, 2019
ea83164
Handle the unknown objects / variant for variant conversions and prev…
bclothier Aug 27, 2019
8a31fbe
Improve the abstraction over the type caching to better support per-p…
bclothier Aug 27, 2019
0bf1e21
Refactor out the setup work from the ComMock into its own builder
bclothier Aug 27, 2019
501ccdd
Create entry points for child mock setups
bclothier Aug 27, 2019
9e52fdf
Create new test for child mock setup
bclothier Aug 27, 2019
36f0692
Update Moq version
bclothier Aug 27, 2019
38f4e35
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Aug 27, 2019
619d39a
Unsabotage the test that should be failing - it would pass if litera…
bclothier Aug 27, 2019
af84f03
Fix up the CustomQueryInterface for handling of VBA types -- VB likes…
bclothier Aug 28, 2019
ece7b7c
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Aug 29, 2019
3b5b8d2
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Aug 30, 2019
931227a
Fix up IoC due to bad merging
bclothier Aug 30, 2019
0ad8736
Merge branch 'next' of https://github.com/rubberduck-vba/Rubberduck i…
bclothier Sep 1, 2019
b099cf2
First part of handling the by ref parameters. Create a ItByRef class …
bclothier Sep 2, 2019
10a7dbf
Additional tests for object types
bclothier Sep 2, 2019
8dd4663
Update to Moq 4.13 and adjust the expression resolution for It.Is whi…
bclothier Sep 3, 2019
915b895
Develop a working version of ItByRef class. The idea was correct but …
bclothier Sep 3, 2019
975e4d8
Revise the ItByRef, set up more tests for the ref cases
bclothier Sep 6, 2019
48da45d
A viable proof of concept for providing CW-injected objects to COM co…
bclothier Sep 6, 2019
2b6ac70
addressed merge conflict in RubberduckIoCInstaller usings.
retailcoder Mar 23, 2021
8662997
removed bad using (merge artifact)
retailcoder Mar 23, 2021
438c450
added initial (broken) implementation for IComMock.Verify
retailcoder Mar 26, 2021
7fa0e32
ComMock.Verify works!
retailcoder Mar 26, 2021
45e69f5
fixed (?) broken test
retailcoder Mar 26, 2021
7d0b34d
Added MockProvider to test template
retailcoder Mar 26, 2021
282f99a
added invalidation mechanism
retailcoder Mar 27, 2021
86c3eb9
clear type cache on parse
retailcoder Mar 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Rubberduck.Core/AddRemoveReferences/ReferenceModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Rubberduck.Parsing.ComReflection;
using Rubberduck.Parsing.ComReflection.TypeLibReflection;
using Rubberduck.VBEditor;
using Rubberduck.VBEditor.SafeComWrappers;
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
Expand Down
100 changes: 0 additions & 100 deletions Rubberduck.Core/AddRemoveReferences/RegisteredLibraryFinderService.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Windows.Forms;
using NLog;
using Rubberduck.AddRemoveReferences;
using Rubberduck.Parsing.ComReflection.TypeLibReflection;
using Rubberduck.Parsing.Symbols;
using Rubberduck.Parsing.VBA;
using Rubberduck.Settings;
Expand Down
6 changes: 6 additions & 0 deletions Rubberduck.Core/UI/Command/ComCommands/ReparseCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Runtime.InteropServices;
using Rubberduck.Interaction;
using Rubberduck.Parsing.ComReflection.TypeLibReflection;
using Rubberduck.Parsing.VBA;
using Rubberduck.Resources;
using Rubberduck.Settings;
Expand Down Expand Up @@ -30,6 +31,7 @@ public class ReparseCommand : ComCommandBase
private readonly IMessageBox _messageBox;
private readonly RubberduckParserState _state;
private readonly GeneralSettings _settings;
private static readonly ICachedTypeService TypeCacheService = CachedTypeService.Instance;

public ReparseCommand(
IVBE vbe,
Expand Down Expand Up @@ -93,6 +95,10 @@ protected override void OnExecute(object parameter)
}
}
}
foreach (var project in _state.Projects)
{
TypeCacheService.TryInvalidate(project.Name);
}
_state.OnParseRequested(this);
}

Expand Down
195 changes: 195 additions & 0 deletions Rubberduck.Main/ComClientLibrary/UnitTesting/Mocks/ComMock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
using Moq;
using Rubberduck.Resources.Registration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;

// ReSharper disable InconsistentNaming

namespace Rubberduck.ComClientLibrary.UnitTesting.Mocks
{
[
ComVisible(true),
Guid(RubberduckGuid.ComMockGuid),
ProgId(RubberduckProgId.ComMockProgId),
ClassInterface(ClassInterfaceType.None),
ComDefaultInterface(typeof(IComMock))
]
public class ComMock : IComMock
{
private readonly ComMocked mocked;
private readonly SetupArgumentResolver _resolver;
private readonly SetupExpressionBuilder _setupBuilder;
private readonly IMockProviderInternal _provider;

internal ComMock(IMockProviderInternal provider, string project, string progId, Mock mock, Type type, IEnumerable<Type> supportedInterfaces)
{
Project = project;
ProgId = progId;
Mock = mock;
_provider = provider;
_resolver = new SetupArgumentResolver();
_setupBuilder = new SetupExpressionBuilder(type, supportedInterfaces, _resolver);
MockedType = type;

Mock.As<IComMocked>().Setup(x => x.Mock).Returns(this);
mocked = new ComMocked(this, supportedInterfaces);
}

public string Project { get; }

public string ProgId { get; }

/// <remarks>
/// Refer to remarks in <see cref="SetupArgumentResolver.ResolveArgs"/> for how the
/// parameter <paramref name="Args"/> is handled.
/// </remarks>
public void Setup(string Name, object Args = null)
{
var args = _resolver.ResolveArgs(Args);
var setupDatas = _setupBuilder.CreateExpression(Name, args);

foreach (var setupData in setupDatas)
{
var builder = MockExpressionBuilder.Create(Mock);
builder.As(setupData.DeclaringType)
.Setup(setupData.SetupExpression, setupData.Args)
.Execute();
}
}

/// <remarks>
/// Refer to remarks in <see cref="SetupArgumentResolver.ResolveArgs"/> for how the
/// parameter <paramref name="Args"/> is handled.
/// </remarks>
public void SetupWithReturns(string Name, object Value, object Args = null)
{
var args = _resolver.ResolveArgs(Args);
var setupDatas = _setupBuilder.CreateExpression(Name, args);

foreach (var setupData in setupDatas)
{
var builder = MockExpressionBuilder.Create(Mock);
builder.As(setupData.DeclaringType)
.Setup(setupData.SetupExpression, setupData.Args, setupData.ReturnType)
.Returns(Value, setupData.ReturnType)
.Execute();
}
}

/// <remarks>
/// Refer to remarks in <see cref="SetupArgumentResolver.ResolveArgs"/> for how the
/// parameter <paramref name="Args"/> is handled.
/// </remarks>
public void SetupWithCallback(string Name, Action Callback, object Args = null)
{
var args = _resolver.ResolveArgs(Args);
var setupDatas = _setupBuilder.CreateExpression(Name, args);

foreach (var setupData in setupDatas)
{
var builder = MockExpressionBuilder.Create(Mock);
builder.As(setupData.DeclaringType)
.Setup(setupData.SetupExpression, setupData.Args)
.Callback(Callback)
.Execute();
}
}

public IComMock SetupChildMock(string Name, object Args)
{
Type type;
var memberInfo = MockedType.GetMember(Name).FirstOrDefault();
if (memberInfo == null)
{
memberInfo = MockedType.GetInterfaces().SelectMany(face => face.GetMember(Name)).First();
}

switch (memberInfo)
{
case FieldInfo fieldInfo:
type = fieldInfo.FieldType;
break;
case PropertyInfo propertyInfo:
type = propertyInfo.PropertyType;
break;
case MethodInfo methodInfo:
type = methodInfo.ReturnType;
break;
default:
throw new InvalidOperationException($"Couldn't resolve member {Name} and acquire a type to mock.");
}

var childMock = _provider.MockChildObject(this, type);
var target = GetMockedObject(childMock, type);
SetupWithReturns(Name, target, Args);

return childMock;
}

private object GetMockedObject(IComMock mock, Type type)
{
var pUnkSource = IntPtr.Zero;
var pUnkTarget = IntPtr.Zero;

try
{
pUnkSource = Marshal.GetIUnknownForObject(mock.Object);
var iid = type.GUID;
Marshal.QueryInterface(pUnkSource, ref iid, out pUnkTarget);
return Marshal.GetTypedObjectForIUnknown(pUnkTarget, type);
}
finally
{
if (pUnkTarget != IntPtr.Zero) Marshal.Release(pUnkTarget);
if (pUnkSource != IntPtr.Zero) Marshal.Release(pUnkSource);
}
}

public void Verify(string Name, ITimes Times, [MarshalAs(UnmanagedType.Struct), Optional] object Args)
{
var args = _resolver.ResolveArgs(Args);
var setupDatas = _setupBuilder.CreateExpression(Name, args);

var throwingExecutions = 0;
MockException lastException = null;
foreach (var setupData in setupDatas)
{
try
{
var builder = MockExpressionBuilder.Create(Mock);
builder.As(setupData.DeclaringType)
.Verify(setupData.SetupExpression, Times, setupData.Args)
.Execute();

Rubberduck.UnitTesting.AssertHandler.OnAssertSucceeded();
}
catch (TargetInvocationException exception)
{
if (exception.InnerException is MockException inner)
{
throwingExecutions++;
lastException = inner;
}
else
{
throw;
}
}
}
if (setupDatas.Count() == throwingExecutions)
{
// if all mocked interfaces failed the .Verify call, then none of them succeeded:
Rubberduck.UnitTesting.AssertHandler.OnAssertFailed(lastException.Message);
}
}

public object Object => mocked;

internal Mock Mock { get; }

internal Type MockedType { get; }
}
}
Loading