arseni-mourzenko / mockeverything Goto Github PK
View Code? Open in Web Editor NEWA tampering library which helps unit testing legacy code which relies too much on .NET Framework
License: MIT License
A tampering library which helps unit testing legacy code which relies too much on .NET Framework
License: MIT License
When dealing with classes containing indexer overloads, an exception is thrown by MockEverything.Inspection.MonoCecil.Type.FindPropertyByName(string) : PropertyDefinition
because Single
is applied to a sequence containing multiple elements.
A way to reproduce this issue it to call Type.FindMethods()
on a class containing several indexers, such as:
public class Demo
{
public string this[int i] { get { return string.Empty; } }
public string this[string i] { get { return string.Empty; } }
}
In C#, the arguments of instance methods start by the instance itself. In other words, for an instance method which takes a string as a parameter, in the corresponding IL code, ldarg.0
refers to this
, and ldarg.1
refers to the actual string. On the other hand, if the same method is static, ldarg.0
refers directly to the string.
For example, in the following code:
public class DemoInstance
{
public void SayHello(string name)
{
Console.WriteLine("Hello, {0}!", name);
}
}
public static class DemoStatic
{
public static void SayHello(string name)
{
Console.WriteLine("Hello, {0}!", name);
}
}
the instance method is translated into:
IL_0000: nop
IL_0001: ldstr "Hello, {0}!"
IL_0006: ldarg.1
IL_0007: call void [mscorlib]System.Console::WriteLine(string, object)
IL_000c: nop
IL_000d: ret
while the static method becomes:
IL_0000: nop
IL_0001: ldstr "Hello, {0}!"
IL_0006: ldarg.0
IL_0007: call void [mscorlib]System.Console::WriteLine(string, object)
IL_000c: nop
IL_000d: ret
Since all proxies are static, this leads to a bug which can be reproduced by using the arguments passed to a method (for example by throwing an exception containing in its message all the arguments). The bug is very weird: either it leads to a crash, or the values of the arguments are totally creepy.
When proxy methods correspond to an instance method in the tampered assembly, arguments should be shifted.
It seems that when an unsigned assembly is tampered, the resulting assembly is invalid.
Following #6, if a proxy method contains and uses more than three arguments, the following exception is thrown:
Error 3 opcode at Mono.Cecil.Cil.Instruction.Create(OpCode opcode, Int32 value)
at MockEverything.Inspection.MonoCecil.Method.ShiftArguments(Instruction instruction) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Method.cs:line 225
at MockEverything.Inspection.MonoCecil.Method.ReplaceCollectionContents[TElement](IEnumerable`1 source, Collection`1 destination, Func`2 transform) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Method.cs:line 260
at MockEverything.Inspection.MonoCecil.Method.ReplaceBody(MethodDefinition definition) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Method.cs:line 195
at MockEverything.Inspection.MonoCecil.Method.ReplaceBody(IMethod other) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Method.cs:line 177
at MockEverything.Engine.Tampering.Tampering.Rewrite(Assembly assembly) in C:\Git\mockeverything\MockEverything\Source\Engine\Tampering\Tampering.cs:line 161
at MockEverything.Engine.Tampering.Tampering.Tamper(String[] dependenciesLocations) in C:\Git\mockeverything\MockEverything\Source\Engine\Tampering\Tampering.cs:line 77
at MockEverything.BuildTask.TamperingTask.ProcessProxy(Tampering tampering) in C:\Git\mockeverything\MockEverything\Source\BuildTask\TamperingTask.cs:line 100
at MockEverything.BuildTask.TamperingTask.Execute() in C:\Git\mockeverything\MockEverything\Source\BuildTask\TamperingTask.cs:line 60 [...]
Consider explaining in documentation a way to see in Visual Studio the logs produced by the custom build task, as well as the way to quickly run just the task, separately from Visual Studio.
When the proxy has a method which uses params
, the following exception is thrown:
Error 3 Sequence contains no matching element at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
at MockEverything.Inspection.MonoCecil.Type.FindPropertyByName(String name, IEnumerable`1 parameters) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Type.cs:line 334
at MockEverything.Inspection.MonoCecil.Type.FindAttributesOfGetterOrSetter(MethodDefinition methodDefinition) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Type.cs:line 319
at MockEverything.Inspection.MonoCecil.Type.FindAttributesOfMethod(MethodDefinition methodDefinition) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Type.cs:line 299
at MockEverything.Inspection.MonoCecil.Type.MatchAttributesFilter(MethodDefinition methodDefinition, ICollection`1 attributes) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Type.cs:line 282
at MockEverything.Inspection.MonoCecil.Type.<>c__DisplayClass10_0.<FindMethods>b__1(MethodDefinition definition) in C:\Git\mockeverything\MockEverything\Source\Inspection\MonoCecil\Type.cs:line 123
at System.Linq.Enumerable.<>c__DisplayClassf`1.<CombinePredicates>b__e(TSource x)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at MockEverything.Engine.Browsers.MethodMatching.FindMatch(IMethod proxy, IType targetType) in C:\Git\mockeverything\MockEverything\Source\Engine\Matching\MethodMatching.cs:line 33
at MockEverything.Engine.Browsers.Browser`2.CreateMatch(TElement proxyType) in C:\Git\mockeverything\MockEverything\Source\Engine\Browsers\Browser{TElement,TContainer}.cs:line 92
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
at MockEverything.Engine.Tampering.Tampering.Rewrite(Assembly assembly) in C:\Git\mockeverything\MockEverything\Source\Engine\Tampering\Tampering.cs:line 158
at MockEverything.Engine.Tampering.Tampering.Tamper(String[] dependenciesLocations) in C:\Git\mockeverything\MockEverything\Source\Engine\Tampering\Tampering.cs:line 77
at MockEverything.BuildTask.TamperingTask.ProcessProxy(Tampering tampering) in C:\Git\mockeverything\MockEverything\Source\BuildTask\TamperingTask.cs:line 100
at MockEverything.BuildTask.TamperingTask.Execute() in C:\Git\mockeverything\MockEverything\Source\BuildTask\TamperingTask.cs:line 60
...
Based on #9, implement AOP on the methods within the proxy, making it possible to log entry points and exit points for every method.
Console.WriteLine()
and Trace.WriteLine()
cannot be used within the proxies, since the messages never appear in the actual console or trace.
Implement an exchanger which is able to collect logs (preferably transparently by subscribing to console and trace messages) and send it to the caller.
The current (documented) limitation is that the product cannot be used to tamper mscorlib. This is unfortunate, given the amount of legacy code which relies on “basic” .NET Framework classes such as System.IO.File
, preventing it from being tested.
According to the documentation, this limitation comes from a problem within ILRepack. A fork of ILRepack should be done in order to make it possible to tamper mscorlib.
When dealing with large assemblies such as Microsoft.SharePoint
, the time it takes to tamper it is terrible (up to one minute on an average machine).
The solution could be to create a stripped version of ILRepack which, eventually, merges proxy assembly to target one, instead of creating an empty assembly.
Another solution, which seems too scary, is to inject proxy code directly inside the assembly. This was attempted in the early prototypes, and appeared to be overly complicated.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.