Merge remote-tracking branch 'origin/mockCtorIntegration'

This commit is contained in:
Scott Bilas 2018-08-02 13:42:28 +02:00
Родитель ead6b54b39 941bcb8109
Коммит 6943026714
9 изменённых файлов: 262 добавлений и 77 удалений

Просмотреть файл

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Mono.Cecil;
using NSubstitute.Core;
using NSubstitute.Elevated.WeaverInternals;
using NSubstitute.Exceptions;
@ -9,6 +10,7 @@ using NSubstitute.Proxies;
using NSubstitute.Proxies.CastleDynamicProxy;
using NSubstitute.Proxies.DelegateProxy;
using Unity.Core;
using TypeAttributes = Mono.Cecil.TypeAttributes;
namespace NSubstitute.Elevated
{
@ -23,6 +25,15 @@ namespace NSubstitute.Elevated
m_CallFactory = new CallFactory(substitutionContext);
}
void AddMockPlaceholderToAssembly(AssemblyDefinition targetAssembly)
{
var mockPlaceholder = new TypeDefinition("NSubstitute.Elevated.WeaverInternals", "MockPlaceholderType", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit)
{
BaseType = targetAssembly.MainModule.TypeSystem.Object
};
targetAssembly.MainModule.Types.Add(mockPlaceholder);
}
object IProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, object[] constructorArguments)
{
// TODO:
@ -58,18 +69,32 @@ namespace NSubstitute.Elevated
if (additionalInterfaces.Any())
throw new SubstituteException("Cannot add interfaces at runtime to patched types");
if (substituteConfig == SubstituteConfig.OverrideAllCalls)
{
// overriding all calls includes the ctor, so it makes no sense for the user to pass in ctor args
if (constructorArguments.Any())
throw new SubstituteException("Do not pass ctor args when substituting with elevated mocks (or did you mean to use ForPartsOf?)");
switch (substituteConfig) {
case SubstituteConfig.OverrideAllCalls:
// but we use a ctor arg to select the special empty ctor that we patched in
constructorArguments = k_MockedCtorParams;
// overriding all calls includes the ctor, so it makes no sense for the user to pass in ctor args
if (constructorArguments != null && constructorArguments.Any())
throw new SubstituteException("Do not pass ctor args when substituting with elevated mocks (or did you mean to use ForPartsOf?)");
// but we use a ctor arg to select the special empty ctor that we patched in
constructorArguments = k_MockedCtorParams;
break;
case SubstituteConfig.CallBaseByDefault:
var castleDynamicProxyFactory = new CastleDynamicProxyFactory();
return castleDynamicProxyFactory.GenerateProxy(callRouter, typeToProxy, additionalInterfaces, constructorArguments);
case null:
break;
default:
throw new ArgumentOutOfRangeException();
}
// var proxyWrap = Activator.CreateInstanceFrom(patchAllDependentAssemblies[1].Path, typeToProxy.FullName, false,
// BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance, null,
// constructorArguments, null, null);
// proxy = proxyWrap.Unwrap();
proxy = Activator.CreateInstance(typeToProxy, constructorArguments);
GetRouterField(typeToProxy).SetValue(proxy, callRouter);
GetRouterField(proxy.GetType()).SetValue(proxy, callRouter);
}
return proxy;

Просмотреть файл

@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using NSubstitute.Core;
using NSubstitute.Core.Arguments;
using NSubstitute.Elevated.Weaver;
using NSubstitute.Exceptions;
using NSubstitute.Routing;
using Unity.Core;
@ -28,12 +31,14 @@ namespace NSubstitute.Elevated
new ElevatedCallRouterFactory(), ElevatedSubstituteManager, new CallRouterResolver());
}
public static IDisposable AutoHook()
public static IDisposable AutoHook(string assemblyLocation, IEnumerable<string> assemblyPath = null)
{
var hookedContext = SubstitutionContext.Current;
var thisContext = new ElevatedSubstitutionContext(hookedContext);
SubstitutionContext.Current = thisContext;
var patchAllDependentAssemblies = ElevatedWeaver.PatchAllDependentAssemblies(assemblyLocation, PatchTestAssembly.Yes, assemblyPath).ToList();
return new DelegateDisposable(() =>
{
if (SubstitutionContext.Current != thisContext)

Просмотреть файл

@ -1,11 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="../common.targets" />
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations">
<Version>11.1.0</Version>
@ -16,10 +13,9 @@
<PackageReference Include="Mono.Cecil">
<Version>0.10.0-beta6</Version>
</PackageReference>
<PackageReference Include="Shouldly" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Unity.Core\Unity.Core.csproj" />
</ItemGroup>
</Project>
</Project>

Просмотреть файл

@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Mono.Cecil;
using Shouldly;
using Unity.Core;
namespace NSubstitute.Elevated.Weaver
@ -19,9 +20,8 @@ namespace NSubstitute.Elevated.Weaver
public static string GetPatchBackupPathFor(string path)
=> path + k_PatchBackupExtension;
public static IReadOnlyCollection<PatchResult> PatchAllDependentAssemblies(
[NotNull] string testAssemblyPath,
PatchTestAssembly patchTestAssembly = PatchTestAssembly.No) // typically we don't want to patch the test assembly itself, only the systems under test
public static IReadOnlyCollection<PatchResult> PatchAllDependentAssemblies([NotNull] string testAssemblyPath,
PatchTestAssembly patchTestAssembly = PatchTestAssembly.No, IEnumerable<string> assemblyPath = null) // typically we don't want to patch the test assembly itself, only the systems under test
{
var testAssemblyFolder = Path.GetDirectoryName(testAssemblyPath);
if (testAssemblyFolder.IsNullOrEmpty())
@ -75,21 +75,27 @@ namespace NSubstitute.Elevated.Weaver
patchResult = new PatchResult(assemblyToPatchPath, null, PatchState.IgnoredTestAssembly);
else if (MockInjector.IsPatched(assemblyToPatch))
patchResult = new PatchResult(assemblyToPatchPath, null, PatchState.AlreadyPatched);
else
else if (assemblyPath.Contains(assemblyToPatch.Name.Name))
{
mockInjector.Patch(assemblyToPatch);
// atomic write of file with backup
var tmpPath = assemblyToPatchPath + ".tmp";
var tmpPath = assemblyToPatchPath.Split(new[] {".dll"}, StringSplitOptions.None)[0] +
".tmp";
File.Delete(tmpPath);
assemblyToPatch.Write(tmpPath);//$$$$, new WriterParameters { WriteSymbols = true }); // getting exception, haven't looked into it yet
assemblyToPatch.Write(tmpPath); //$$$$, new WriterParameters { WriteSymbols = true }); // getting exception, haven't looked into it yet
assemblyToPatch.Dispose();
var originalPath = GetPatchBackupPathFor(assemblyToPatchPath);
File.Replace(tmpPath, assemblyToPatchPath, originalPath);
Verify(assemblyToPatchPath);
// $$$ TODO: move pdb file too
patchResult = new PatchResult(assemblyToPatchPath, originalPath, PatchState.Patched);
}
else
{ // TODO: Nope
patchResult = default(PatchResult);
}
patchResults.Add(assemblyToPatchPath, patchResult);
}
@ -98,6 +104,83 @@ namespace NSubstitute.Elevated.Weaver
return patchResults.Values;
}
}
// TODO: Fix
const string peVerifyLocation = @"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\PEVerify.exe";
static void Verify(string assemblyName)
{
var p = new Process
{
StartInfo =
{
Arguments = $"/nologo \"{assemblyName}\"",
UseShellExecute = false,
CreateNoWindow = true,
FileName = peVerifyLocation,
RedirectStandardError = true,
RedirectStandardOutput = true
}
};
var error = "";
var output = "";
p.OutputDataReceived += (_, e) => output += $"{e.Data}\n";
p.ErrorDataReceived += (_, e) => error += $"{e.Data}\n";
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
Console.WriteLine(assemblyName);
p.ExitCode.ShouldBe(0, () => $"{error}\n{output}");
}
public static IReadOnlyCollection<PatchResult> PatchAssemblies(
[NotNull] List<string> testAssemblyPaths)
{
var testAssemblyPath = testAssemblyPaths[0];
var testAssemblyFolder = Path.GetDirectoryName(testAssemblyPath);
if (testAssemblyFolder.IsNullOrEmpty())
throw new Exception("Unable to find folder for test assembly");
testAssemblyFolder = Path.GetFullPath(testAssemblyFolder);
// scope
{
var thisAssemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (thisAssemblyFolder.IsNullOrEmpty())
throw new Exception("Can only patch assemblies on disk");
thisAssemblyFolder = Path.GetFullPath(thisAssemblyFolder);
// keep things really simple, at least for now
if (string.Compare(testAssemblyFolder, thisAssemblyFolder, StringComparison.OrdinalIgnoreCase) != 0)
throw new Exception("All assemblies must be in the same folder");
}
var nsubElevatedPath = Path.Combine(testAssemblyFolder, "NSubstitute.Elevated.dll");
using (var nsubElevatedAssembly = AssemblyDefinition.ReadAssembly(nsubElevatedPath))
{
var mockInjector = new MockInjector(nsubElevatedAssembly);
foreach (var assemblyPath in testAssemblyPaths)
{
var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyPath);
mockInjector.Patch(assemblyDefinition);
// atomic write of file with backup
var tmpPath = assemblyPath.Split(new[] { ".dll" }, StringSplitOptions.None)[0] + ".tmp";
File.Delete(tmpPath);
assemblyDefinition.Write(tmpPath);//$$$$, new WriterParameters { WriteSymbols = true }); // getting exception, haven't looked into it yet
assemblyDefinition.Dispose();
/*var originalPath = GetPatchBackupPathFor(assemblyToPatchPath);
File.Replace(tmpPath, assemblyToPatchPath, originalPath);*/
// $$$ TODO: move pdb file too
}
return null;
}
}
}
public enum PatchState

Просмотреть файл

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Policy;
@ -52,7 +53,7 @@ namespace NSubstitute.Elevated.Weaver
.ToList(); // copy to a list in case patch work we do would invalidate the enumerator
foreach (var type in typesToProcess)
Patch(type);
Patch(type, assembly);
// add an attr to mark the assembly as patched
@ -87,7 +88,7 @@ namespace NSubstitute.Elevated.Weaver
return IsPatched(assembly);
}
void Patch(TypeDefinition type)
void Patch(TypeDefinition type, AssemblyDefinition assembly)
{
if (type.IsInterface)
return;
@ -103,12 +104,12 @@ namespace NSubstitute.Elevated.Weaver
try
{
foreach (var method in type.Methods)
Patch(method);
Patch(method, assembly);
void AddField(string fieldName, FieldAttributes fieldAttributes)
{
type.Fields.Add(new FieldDefinition(fieldName,
FieldAttributes.Private | FieldAttributes.NotSerialized | fieldAttributes,
FieldAttributes.Private | fieldAttributes,
type.Module.TypeSystem.Object));
}
@ -175,12 +176,72 @@ namespace NSubstitute.Elevated.Weaver
type.Methods.Add(ctor);
}
void Patch(MethodDefinition method)
void Patch(MethodDefinition method, AssemblyDefinition assembly)
{
if (method.IsCompilerControlled || method.IsConstructor || method.IsAbstract)
return;
// $$$ DOWIT
method.Body.InitLocals = true;
var originalType = assembly.MainModule.ImportReference(Type.GetType("System.Type"));
var getTypeFromHandle = assembly.MainModule.ImportReference(originalType.Resolve().Methods.Single(m => m.Name == "GetTypeFromHandle"));
//var getTypeFromHandle = assembly.MainModule.Import(new MethodReference("GetTypeFromHandle", type, type) { Parameters = { new ParameterDefinition(runtimeTypeHandle) } });
var emptyTypes = assembly.MainModule.ImportReference(originalType.Resolve().Fields.Single(f => f.Name == "EmptyTypes"));
var v1 = new VariableDefinition(assembly.MainModule.TypeSystem.Object);
method.Body.Variables.Add(v1);
var bodyInstructions = new List<Instruction>(method.Body.Instructions);
method.Body.Instructions.Clear();
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldtoken, method.DeclaringType));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, getTypeFromHandle));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldtoken, method.ReturnType));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, getTypeFromHandle));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloca_S, v1));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldsfld, emptyTypes));
// TODO: Parameter specific
if (method.Parameters.Count > 0)
{
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_1));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Newarr, assembly.MainModule.TypeSystem.Object));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Dup));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); // arg
method.Body.Instructions.Add(Instruction.Create(OpCodes.Box, method.Parameters[0].ParameterType));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Stelem_Ref));
}
else
{
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Newarr, assembly.MainModule.TypeSystem.Object));
}
// End of parameter include
method.Body.Instructions.Add(Instruction.Create(OpCodes.Call, assembly.MainModule.ImportReference(m_PatchedAssemblyBridgeTryMock)));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Nop));
var count = method.Body.Instructions.Count;
var hasReturnValue = method.ReturnType != assembly.MainModule.TypeSystem.Void;
if (hasReturnValue)
{
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldloc_S, v1));
method.Body.Instructions.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType));
}
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
foreach (var instruction in bodyInstructions)
{
method.Body.Instructions.Add(instruction);
}
method.Body.Instructions[count - 1] = Instruction.Create(OpCodes.Brfalse_S, method.Body.Instructions[count + (hasReturnValue ? 3 : 1)]);
/*method.Body.Instructions.Clear();
ConvertReturnTypeToDefault(method.ReturnType, method.Body.Instructions);
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));*/
}
}
}

Просмотреть файл

@ -1,6 +1,5 @@
using System;
using SystemUnderTest;
using NSubstitute.Elevated.WeaverInternals;
using NSubstitute.Exceptions;
using NUnit.Framework;
using Shouldly;
@ -15,8 +14,7 @@ namespace NSubstitute.Elevated.Tests
[OneTimeSetUp]
public void Setup()
{
m_Dispose = ElevatedSubstitutionContext.AutoHook();
PatchedAssemblyBridgeX.TryMock = PatchedAssemblyBridge.TryMock;
m_Dispose = ElevatedSubstitutionContext.AutoHook(typeof(BasicTests).Assembly.Location, new [] {"SystemUnderTest"});
}
[OneTimeTearDown]
@ -60,6 +58,16 @@ namespace NSubstitute.Elevated.Tests
sub.Value.ShouldBe(0);
}
[Test]
public void ClassWithDefaultCtor_MockedMethod_ReturnsOverriddenValue()
{
var sub = Substitute.For<ClassWithDefaultCtor>();
sub.Value.Returns(24);
sub.Value.ShouldBe(24);
}
[Test]
public void ClassWithNoDefaultCtor_TypeDoesNotChange()
{
@ -92,7 +100,7 @@ namespace NSubstitute.Elevated.Tests
[Test]
public void ClassWithCtorParams_WhenMocked_ShouldThrow()
{
Should.Throw<SubstituteException>(() => Substitute.For<ClassWithNoDefaultCtor>(null));
// Should.Throw<MissingMethodException>(() => Substitute.For<ClassWithNoDefaultCtor>());
Should.Throw<SubstituteException>(() => Substitute.For<ClassWithNoDefaultCtor>("test"));
Should.Throw<SubstituteException>(() => Substitute.For<ClassWithNoDefaultCtor>(null, null));
}
@ -104,16 +112,16 @@ namespace NSubstitute.Elevated.Tests
// if unpatched, then mocking will run standard nsubstitute behavior (i.e. proxying done via dynamicproxy generator, which inherits proxy type from the real type).
var subEmpty = Substitute.For<EmptyClass>();
subEmpty.GetType().BaseType.ShouldBe(typeof(EmptyClass));
subEmpty.GetType().ShouldBe(typeof(EmptyClass));
var subNoCtor1 = Substitute.For<ClassWithNoDefaultCtorNoMethods>(null);
subNoCtor1.GetType().BaseType.ShouldBe(typeof(ClassWithNoDefaultCtorNoMethods));
subNoCtor1.GetType().ShouldBe(typeof(ClassWithNoDefaultCtorNoMethods));
var subNoCtor2 = Substitute.For<ClassWithNoDefaultCtorNoMethods>("test");
subNoCtor2.GetType().BaseType.ShouldBe(typeof(ClassWithNoDefaultCtorNoMethods));
// var subNoCtor2 = Substitute.For<ClassWithNoDefaultCtorNoMethods>("test"); TODO: This will cause an exception as ForPartsOf should be used. Maybe do that here instead?
// subNoCtor2.GetType().ShouldBe(typeof(ClassWithNoDefaultCtorNoMethods));
var subNoCtor3 = Substitute.For<ClassWithNoDefaultCtorNoMethods>(null, null);
subNoCtor3.GetType().BaseType.ShouldBe(typeof(ClassWithNoDefaultCtorNoMethods));
// var subNoCtor3 = Substitute.For<ClassWithNoDefaultCtorNoMethods>(null, null);
// subNoCtor3.GetType().ShouldBe(typeof(ClassWithNoDefaultCtorNoMethods));
}
[Test]
@ -131,7 +139,7 @@ namespace NSubstitute.Elevated.Tests
var sub = Substitute.For<ClassWithDependency>();
// ReSharper disable once PossibleNullReferenceException
sub.GetType().GetMethod("Dummy").ReturnType.FullName.ShouldBe("mycodedep.DependentType");
sub.GetType().GetMethod("Dummy").ReturnType.FullName.ShouldBe("DependentAssembly.DependentType");
// $$$ TODO: test that the type is itself patched (look for __mockthingy)
}
@ -163,7 +171,7 @@ namespace NSubstitute.Elevated.Tests
sub.ReturnMethod(3).ShouldBe(8);
sub.Modified.ShouldBe(8);
sub.ReturnMethod(Arg.Is(4)).Returns(10);
sub.ReturnMethod(4).Returns(10);
sub.ReturnMethod(4).ShouldBe(10);
sub.Modified.ShouldBe(8);
}

Просмотреть файл

@ -1,6 +1,6 @@
using System;
using System.Diagnostics;
using Microsoft.Build.Utilities;
using Shouldly;
namespace NSubstitute.Elevated.Tests.Utilities
{
@ -24,29 +24,37 @@ namespace NSubstitute.Elevated.Tests.Utilities
public static class PeVerify
{
public static void Verify(string assemblyToTestPath)
// TODO: Fix
const string k_PeVerifyLocation = @"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\PEVerify.exe";
public static void Verify(string assemblyName)
{
var peVerifyPath = ToolLocationHelper.GetPathToDotNetFrameworkSdkFile("peverify.exe", TargetDotNetFrameworkVersion.Version45);
var psi = new ProcessStartInfo(peVerifyPath, $"/nologo \"{assemblyToTestPath}\"")
var p = new Process
{
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = true,
UseShellExecute = false
StartInfo =
{
Arguments = $"/nologo \"{assemblyName}\"",
UseShellExecute = false,
CreateNoWindow = true,
FileName = k_PeVerifyLocation,
RedirectStandardError = true,
RedirectStandardOutput = true
}
};
using (var process = Process.Start(psi))
{
if (process != null)
{
process.WaitForExit();
if (process.ExitCode != 0)
{
var stdout = process.StandardOutput.ReadToEnd(); // peverify apparently doesn't write to stderr..
throw new PeVerifyException($"Failure during PEVerify of {assemblyToTestPath}", process.ExitCode, stdout);
}
}
}
var error = "";
var output = "";
p.OutputDataReceived += (_, e) => output += $"{e.Data}\n";
p.ErrorDataReceived += (_, e) => error += $"{e.Data}\n";
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
Console.WriteLine(assemblyName);
p.ExitCode.ShouldBe(0, () => $"{error}\n{output}");
}
}
}

Просмотреть файл

@ -1,6 +1,7 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
@ -47,7 +48,7 @@ namespace NSubstitute.Elevated.Tests.Utilities
PeVerify.Verify(m_TestAssemblyPath); // pre-check..sometimes we can compile code that doesn't verify
var results = ElevatedWeaver.PatchAllDependentAssemblies(m_TestAssemblyPath, PatchTestAssembly.Yes);
var results = ElevatedWeaver.PatchAllDependentAssemblies(m_TestAssemblyPath, PatchTestAssembly.Yes, new [] { new FileInfo(m_TestAssemblyPath).Name.Replace(".dll", string.Empty) });
results.Count.ShouldBe(2);
results.ShouldContain(new PatchResult("mscorlib", null, PatchState.IgnoredOutsideAllowedPaths));
results.ShouldContain(new PatchResult(m_TestAssemblyPath, ElevatedWeaver.GetPatchBackupPathFor(m_TestAssemblyPath), PatchState.Patched));

Просмотреть файл

@ -1,5 +1,7 @@
using System;
using NSubstitute.Elevated.WeaverInternals;
//using NSubstitute.Elevated.WeaverInternals;
//using NSubstitute.Elevated.WeaverInternals;
#if TEST_ICALLS
using System.Runtime.CompilerServices;
@ -33,7 +35,7 @@ namespace SystemUnderTest
public int Value = 234;
void Dummy() {}
public void Dummy() {}
}
public class ClassWithNoDefaultCtor
@ -87,36 +89,32 @@ namespace SystemUnderTest
public class SimpleClass
{
static object __mock__staticData;
object __mock__data;
public int Modified;
// actual
//public void VoidMethod() => ++Modified;
//public int ReturnMethod() => ++Modified;
// hack until patching works
//actual
public void VoidMethod() => ++Modified;
public int ReturnMethod() => ++Modified;
//hack until patching works
public void VoidMethod(int count)
{
if (PatchedAssemblyBridgeX.TryMock(typeof(SimpleClass), this, typeof(void), out var _, Type.EmptyTypes, new object[] { count }))
return;
/*if (PatchedAssemblyBridgeX.TryMock(typeof(SimpleClass), this, typeof(void), out var _, Type.EmptyTypes, new object[] { count }))
return;*/
Modified += count;
}
public int ReturnMethod(int count)
{
if (PatchedAssemblyBridgeX.TryMock(typeof(SimpleClass), this, typeof(int), out var returnValue, Type.EmptyTypes, new object[] { count }))
return (int)returnValue;
/*if (PatchedAssemblyBridgeX.TryMock(typeof(SimpleClass), this, typeof(int), out var returnValue, Type.EmptyTypes, new object[] { count }))
return (int)returnValue;#1#*/
return Modified += count;
}
}
}
namespace NSubstitute.Elevated.WeaverInternals
/*namespace NSubstitute.Elevated.WeaverInternals
{
public static class PatchedAssemblyBridgeX
{
@ -124,4 +122,4 @@ namespace NSubstitute.Elevated.WeaverInternals
public static TryMockProc TryMock;
}
}
}*/