Skip to content

Commit c49e48b

Browse files
authored
Merge pull request #2926 from comintern/next
Minor Fake\Stub refactors, implement a handful of system impacting functions.
2 parents 11d6187 + 89ea6cb commit c49e48b

29 files changed

+847
-55
lines changed

RetailCoder.VBE/Rubberduck.csproj

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -499,20 +499,31 @@
499499
</Compile>
500500
<Compile Include="UI\Refactorings\ReorderParameters\ReorderParametersViewModel.cs" />
501501
<Compile Include="UI\SelectionChangeService.cs" />
502-
<Compile Include="UnitTesting\Fakes\FakeBase.cs" />
503-
<Compile Include="UnitTesting\Fakes\FakesProvider.cs" />
504-
<Compile Include="UnitTesting\Fakes\FakesProviderFactory.cs" />
505-
<Compile Include="UnitTesting\Fakes\IFake.cs" />
506-
<Compile Include="UnitTesting\Fakes\IFakesProvider.cs" />
502+
<Compile Include="UnitTesting\Fakes\CurDir.cs" />
503+
<Compile Include="UnitTesting\Fakes\DoEvents.cs" />
504+
<Compile Include="UnitTesting\Fakes\Environ.cs" />
505+
<Compile Include="UnitTesting\FakeBase.cs" />
506+
<Compile Include="UnitTesting\FakesProvider.cs" />
507+
<Compile Include="UnitTesting\FakesProviderFactory.cs" />
508+
<Compile Include="UnitTesting\Fakes\Shell.cs" />
509+
<Compile Include="UnitTesting\IFake.cs" />
510+
<Compile Include="UnitTesting\IFakesProvider.cs" />
507511
<Compile Include="UnitTesting\Fakes\InputBox.cs" />
508-
<Compile Include="UnitTesting\Fakes\IVerify.cs" />
512+
<Compile Include="UnitTesting\IVerify.cs" />
509513
<Compile Include="UnitTesting\Fakes\MsgBox.cs" />
510-
<Compile Include="UnitTesting\Fakes\ReturnTypeConverter.cs" />
511-
<Compile Include="UnitTesting\Fakes\Verifier.cs" />
514+
<Compile Include="UnitTesting\ReturnTypeConverter.cs" />
515+
<Compile Include="UnitTesting\Fakes\Timer.cs" />
516+
<Compile Include="UnitTesting\Stubs\ChDir.cs" />
517+
<Compile Include="UnitTesting\Stubs\ChDrive.cs" />
518+
<Compile Include="UnitTesting\Stubs\Kill.cs" />
519+
<Compile Include="UnitTesting\Stubs\MkDir.cs" />
520+
<Compile Include="UnitTesting\Stubs\RmDir.cs" />
521+
<Compile Include="UnitTesting\Stubs\SendKeys.cs" />
522+
<Compile Include="UnitTesting\Verifier.cs" />
512523
<Compile Include="UnitTesting\PermissiveObjectComparer.cs" />
513524
<Compile Include="UnitTesting\Stubs\Beep.cs" />
514-
<Compile Include="UnitTesting\Stubs\IStub.cs" />
515-
<Compile Include="UnitTesting\Stubs\StubBase.cs" />
525+
<Compile Include="UnitTesting\IStub.cs" />
526+
<Compile Include="UnitTesting\StubBase.cs" />
516527
<Compile Include="VersionCheck\IVersionCheck.cs" />
517528
<Compile Include="UI\Command\MenuItems\CommandBars\AppCommandBarBase.cs" />
518529
<Compile Include="UI\Command\MenuItems\CommandBars\ContextSelectionLabelMenuItem.cs" />

RetailCoder.VBE/UnitTesting/Fakes/FakeBase.cs renamed to RetailCoder.VBE/UnitTesting/FakeBase.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
32
using System.Linq;
43

54
namespace Rubberduck.UnitTesting
@@ -8,8 +7,6 @@ internal abstract class FakeBase : StubBase, IFake
87
{
98
#region Internal
109

11-
internal FakeBase(IntPtr procAddress) : base(procAddress) { }
12-
1310
protected struct ReturnValueInfo
1411
{
1512
public int Invocation { get; }
@@ -78,7 +75,7 @@ private bool TrySetReturnValue(bool any = false)
7875
#region IFake
7976

8077
private static readonly List<ReturnValueInfo> ReturnValues = new List<ReturnValueInfo>();
81-
public virtual void Returns(object value, int invocation = FakesProvider.rdAllInvocations)
78+
public virtual void Returns(object value, int invocation = FakesProvider.AllInvocations)
8279
{
8380
ReturnValues.Add(new ReturnValueInfo(invocation, string.Empty, string.Empty, value));
8481
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using Rubberduck.UI;
4+
5+
namespace Rubberduck.UnitTesting
6+
{
7+
// TODO: This is currently broken. The runtime throws a "bad dll calling convention error when it returns", which leads me to
8+
// believe that it is trying to cast the return value and it isn't marshalling correctly.
9+
internal class CurDir : FakeBase
10+
{
11+
private static readonly IntPtr ProcessAddressString = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcCurrentDir");
12+
private static readonly IntPtr ProcessAddressVariant = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcCurrentDirBstr");
13+
14+
public CurDir()
15+
{
16+
InjectDelegate(new CurDirStringDelegate(CurDirStringCallback), ProcessAddressString);
17+
InjectDelegate(new CurDirVariantDelegate(CurDirStringCallback), ProcessAddressVariant);
18+
}
19+
20+
public override bool PassThrough
21+
{
22+
get { return false; }
23+
// ReSharper disable once ValueParameterNotUsed
24+
set
25+
{
26+
Verifier.SuppressAsserts();
27+
AssertHandler.OnAssertInconclusive(string.Format(RubberduckUI.Assert_InvalidFakePassThrough, "CurDir"));
28+
}
29+
}
30+
31+
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
32+
private delegate string CurDirStringDelegate(IntPtr drive);
33+
34+
public string CurDirStringCallback(IntPtr drive)
35+
{
36+
TrackInvocation(drive);
37+
return ReturnValue?.ToString() ?? string.Empty;
38+
}
39+
40+
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
41+
private delegate string CurDirVariantDelegate(IntPtr drive);
42+
43+
public object CurDirVariantCallback(IntPtr drive)
44+
{
45+
TrackInvocation(drive);
46+
return ReturnValue?.ToString() ?? string.Empty;
47+
}
48+
49+
private void TrackInvocation(IntPtr drive)
50+
{
51+
OnCallBack();
52+
53+
TrackUsage("drive", drive);
54+
}
55+
}
56+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Rubberduck.UnitTesting
5+
{
6+
internal class DoEvents : FakeBase
7+
{
8+
private static readonly IntPtr ProcessAddress = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcDoEvents");
9+
10+
public DoEvents()
11+
{
12+
InjectDelegate(new DoEventsDelegate(DoEventsCallback), ProcessAddress);
13+
}
14+
15+
private readonly ValueTypeConverter<int> _converter = new ValueTypeConverter<int>();
16+
public override void Returns(object value, int invocation = FakesProvider.AllInvocations)
17+
{
18+
_converter.Value = value;
19+
base.Returns((int)_converter.Value, invocation);
20+
}
21+
22+
[DllImport(TargetLibrary, SetLastError = true)]
23+
[return: MarshalAs(UnmanagedType.I4)]
24+
private static extern int rtcDoEvents();
25+
26+
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
27+
[return: MarshalAs(UnmanagedType.I4)]
28+
private delegate int DoEventsDelegate();
29+
30+
public int DoEventsCallback()
31+
{
32+
OnCallBack(true);
33+
34+
if (PassThrough)
35+
{
36+
return rtcDoEvents();
37+
}
38+
return (int)(ReturnValue ?? 0);
39+
}
40+
}
41+
42+
43+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using Rubberduck.UI;
4+
5+
namespace Rubberduck.UnitTesting
6+
{
7+
internal class Environ : FakeBase
8+
{
9+
private static readonly IntPtr ProcessAddressString = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcEnvironBstr");
10+
private static readonly IntPtr ProcessAddressVariant = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcEnvironVar");
11+
12+
public Environ()
13+
{
14+
InjectDelegate(new EnvironStringDelegate(EnvironStringCallback), ProcessAddressString);
15+
InjectDelegate(new EnvironVariantDelegate(EnvironStringCallback), ProcessAddressVariant);
16+
}
17+
18+
public override bool PassThrough
19+
{
20+
get { return false; }
21+
// ReSharper disable once ValueParameterNotUsed
22+
set
23+
{
24+
Verifier.SuppressAsserts();
25+
AssertHandler.OnAssertInconclusive(string.Format(RubberduckUI.Assert_InvalidFakePassThrough, "Environ"));
26+
}
27+
}
28+
29+
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
30+
[return: MarshalAs(UnmanagedType.BStr)]
31+
private delegate string EnvironStringDelegate(IntPtr envstring, IntPtr number);
32+
33+
public string EnvironStringCallback(IntPtr envstring, IntPtr number)
34+
{
35+
TrackInvocation(envstring, number);
36+
return ReturnValue?.ToString() ?? string.Empty;
37+
}
38+
39+
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
40+
private delegate string EnvironVariantDelegate(IntPtr envstring, IntPtr number);
41+
42+
public object EnvironVariantCallback(IntPtr envstring, IntPtr number)
43+
{
44+
TrackInvocation(envstring, number);
45+
return ReturnValue?.ToString() ?? string.Empty;
46+
}
47+
48+
private void TrackInvocation(IntPtr envstring, IntPtr number)
49+
{
50+
OnCallBack();
51+
52+
TrackUsage("envstring", envstring);
53+
TrackUsage("number", number);
54+
}
55+
}
56+
}

RetailCoder.VBE/UnitTesting/Fakes/IFakesProvider.cs

Lines changed: 0 additions & 18 deletions
This file was deleted.

RetailCoder.VBE/UnitTesting/Fakes/InputBox.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ internal class InputBox : FakeBase
88
{
99
private static readonly IntPtr ProcessAddress = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcInputBox");
1010

11-
public InputBox() : base (ProcessAddress)
11+
public InputBox()
1212
{
13-
InjectDelegate(new InputBoxDelegate(InputBoxCallback));
13+
InjectDelegate(new InputBoxDelegate(InputBoxCallback), ProcessAddress);
1414
}
1515

1616
public override bool PassThrough

RetailCoder.VBE/UnitTesting/Fakes/MsgBox.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ internal class MsgBox : FakeBase
99
{
1010
private static readonly IntPtr ProcessAddress = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcMsgBox");
1111

12-
public MsgBox() : base (ProcessAddress)
12+
public MsgBox()
1313
{
14-
InjectDelegate(new MessageBoxDelegate(MsgBoxCallback));
14+
InjectDelegate(new MessageBoxDelegate(MsgBoxCallback), ProcessAddress);
1515
}
1616

1717
public override bool PassThrough
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using Rubberduck.Parsing.ComReflection;
4+
using Rubberduck.Parsing.Grammar;
5+
6+
namespace Rubberduck.UnitTesting
7+
{
8+
internal class Shell : FakeBase
9+
{
10+
private static readonly IntPtr ProcessAddress = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcShell");
11+
12+
public Shell()
13+
{
14+
InjectDelegate(new ShellDelegate(ShellCallback), ProcessAddress);
15+
}
16+
17+
private readonly ValueTypeConverter<double> _converter = new ValueTypeConverter<double>();
18+
public override void Returns(object value, int invocation = FakesProvider.AllInvocations)
19+
{
20+
_converter.Value = value;
21+
base.Returns((double)_converter.Value, invocation);
22+
}
23+
24+
[DllImport(TargetLibrary, SetLastError = true)]
25+
private static extern double rtcShell(IntPtr pathname, short windowstyle);
26+
27+
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
28+
[return: MarshalAs(UnmanagedType.R8)]
29+
private delegate double ShellDelegate(IntPtr pathname, short windowstyle);
30+
31+
public double ShellCallback(IntPtr pathname, short windowstyle)
32+
{
33+
OnCallBack(true);
34+
35+
var path = Marshal.PtrToStringBSTR(pathname);
36+
37+
TrackUsage("pathname", pathname);
38+
TrackUsage("windowstyle", windowstyle, Tokens.Integer);
39+
40+
if (PassThrough)
41+
{
42+
return Convert.ToDouble(rtcShell(pathname, windowstyle));
43+
}
44+
return Convert.ToDouble(ReturnValue ?? 0);
45+
}
46+
}
47+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace Rubberduck.UnitTesting
5+
{
6+
internal class Timer : FakeBase
7+
{
8+
private static readonly IntPtr ProcessAddress = EasyHook.LocalHook.GetProcAddress(TargetLibrary, "rtcGetTimer");
9+
10+
public Timer()
11+
{
12+
InjectDelegate(new TimerDelegate(TimerCallback), ProcessAddress);
13+
}
14+
15+
private readonly ValueTypeConverter<float> _converter = new ValueTypeConverter<float>();
16+
public override void Returns(object value, int invocation = FakesProvider.AllInvocations)
17+
{
18+
_converter.Value = value;
19+
base.Returns((float)_converter.Value, invocation);
20+
}
21+
22+
[DllImport(TargetLibrary, SetLastError = true)]
23+
[return: MarshalAs(UnmanagedType.R4)]
24+
private static extern float rtcGetTimer();
25+
26+
[UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
27+
[return: MarshalAs(UnmanagedType.R4)]
28+
private delegate float TimerDelegate();
29+
30+
public float TimerCallback()
31+
{
32+
OnCallBack(true);
33+
34+
if (PassThrough)
35+
{
36+
return rtcGetTimer();
37+
}
38+
return Convert.ToSingle(ReturnValue ?? 0);
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)