static void AssertRecordedHookInjection(string codeToPatch, string testSource, [CallerMemberName] string testName = null)
        {
            var testAssemblyPath       = CompileAssemblyAndCacheResult(testName, "Simple", new[] { codeToPatch, testSource });
            var hookedTestAssemblyPath = Path.ChangeExtension(testAssemblyPath, ".Injected" + Path.GetExtension(testAssemblyPath));

            using (var assembly = File.OpenRead(testAssemblyPath))
            {
                MockWeaver.InjectFakes(assembly, hookedTestAssemblyPath, Assembly.GetExecutingAssembly().Location);

                Console.WriteLine("Original assembly: {0}", testAssemblyPath);
                Console.WriteLine("Patched assembly: {0}", hookedTestAssemblyPath);

                var patchedAssembly = Assembly.LoadFrom(hookedTestAssemblyPath);

                var testType = patchedAssembly.GetType("T");
                var method   = testType.GetMethod("Test");
                var obj      = Activator.CreateInstance(testType);

                var collector = new List <object[]>();
                CastlePatchedInterceptorRegistry.Register(
                    obj,
                    (_, args) =>
                {
                    collector.Add(args);
                    return(null);
                });

                method.Invoke(obj, new object[0]);
                Assert.That(collector, Is.Not.Empty);
            }
        }
        static void AssertHookInjection(string codeToPatch, string testName, Func <Type[], object[], object> hookFunc, object expectedValueFromHook, object[] args = null, Type[] genArgs = null)
        {
            CastlePatchedInterceptorRegistry.Clear();

            var tree      = CSharpSyntaxTree.ParseText(codeToPatch);
            var code      = (CompilationUnitSyntax)tree.GetRoot();
            var testClass = code.Members.OfType <TypeDeclarationSyntax>().Single();
            var originalMethodDeclaration = (MethodDeclarationSyntax)testClass.Members.SingleOrDefault(m => m.IsKind(SyntaxKind.MethodDeclaration));

            var testAssemblyPath       = CompileAssemblyAndCacheResult(testName, "Simple", new[] { codeToPatch });
            var hookedTestAssemblyPath = Path.ChangeExtension(testAssemblyPath, ".Fake" + Path.GetExtension(testAssemblyPath));

            using (var assembly = File.OpenRead(testAssemblyPath))
            {
                MockWeaver.InjectFakes(assembly, hookedTestAssemblyPath, Assembly.GetExecutingAssembly().Location);

                Console.WriteLine("Original assembly: {0}", testAssemblyPath);
                Console.WriteLine("Patched assembly: {0}", hookedTestAssemblyPath);

                var fakedAssembly = Assembly.LoadFrom(hookedTestAssemblyPath);

                var type = fakedAssembly.GetType(testClass.Identifier.Text);
                if (testClass.TypeParameterList != null && testClass.TypeParameterList.Parameters.Count > 0)
                {
                    type    = fakedAssembly.GetType(testClass.Identifier.Text + "`" + testClass.TypeParameterList.Parameters.Count);
                    genArgs = genArgs ?? new[] { expectedValueFromHook.GetType() };
                    type    = type.MakeGenericType(genArgs);
                }

                MethodInfo method;
                if (originalMethodDeclaration != null)
                {
                    method = type.GetMethod(originalMethodDeclaration.Identifier.ValueText);
                }
                else
                {
                    var originalPropertyDeclaration = (PropertyDeclarationSyntax)testClass.Members.SingleOrDefault(m => m.IsKind(SyntaxKind.PropertyDeclaration));
                    if (originalPropertyDeclaration != null)
                    {
                        var prop = type.GetProperty(originalPropertyDeclaration.Identifier.ValueText);
                        method = prop.GetMethod ?? prop.SetMethod;
                    }
                    else
                    {
                        var originalEvent = (EventFieldDeclarationSyntax)testClass.Members.SingleOrDefault(m => m.IsKind(SyntaxKind.EventFieldDeclaration));
                        var evt           = type.GetEvent(originalEvent.Declaration.Variables[0].Identifier.ValueText);

                        method = evt.AddMethod ?? evt.RemoveMethod;
                    }
                }

                args = args ?? new object[method.GetParameters().Length];

                Action registerHook;
                object obj = null;
                if (method.IsStatic)
                {
                    registerHook = () => CastlePatchedInterceptorRegistry.Register(type, hookFunc);
                }
                else
                {
                    obj          = Activator.CreateInstance(type);
                    registerHook = () => CastlePatchedInterceptorRegistry.Register(obj, hookFunc);
                }

                //var originalValue = method.Invoke(obj, dummyParams);

                registerHook();

                if (method.IsGenericMethodDefinition)
                {
                    method = method.MakeGenericMethod(genArgs);
                }

                var actualValueFromHook = method.Invoke(obj, args);

                if (method.ReturnType != typeof(void))
                {
                    Assert.AreEqual(expectedValueFromHook, actualValueFromHook);
                    //Assert.AreNotEqual(originalValue, actualValueFromHook);
                }
            }
        }