public void Second_pass_should_use_recorded_values_from_previous_pass()
        {
            var storage = new Storage();

            using (var recorder = new RecordingManager(storage))
            {
                var memoryStream = new MemoryStream();

                using (var stream = A.Fake<Stream>(x => x.Wrapping(memoryStream).RecordedBy(recorder)))
                using (var writer = new StreamWriter(stream))
                {
                    writer.Write("Hello world!");
                }

                Assert.That(memoryStream.GetBuffer().Length, Is.Not.LessThanOrEqualTo(0));
            }

            using (var recorder = new RecordingManager(storage))
            {
                var memoryStream = new MemoryStream();
                using (var stream = A.Fake<Stream>(x => x.Wrapping(memoryStream).RecordedBy(recorder)))
                using (var writer = new StreamWriter(stream))
                {
                    writer.Write("Hello world!");
                }

                Assert.That(memoryStream.Length, Is.EqualTo(0));
            }

            foreach (var call in storage.RecordedCalls)
            {
                Console.WriteLine(call.Method.ToString() + " returns: " + call.ReturnValue);
            }
        }
        public void SelfInitializing(
            InMemoryStorage inMemoryStorage,
            ILibraryService realServiceWhileRecording,
            ILibraryService realServiceDuringPlayback,
            int count1ForBook1WhileRecording,
            int count1ForBook1DuringPlayback,
            int count2ForBook1DuringPlayback,
            int count1ForBook2DuringPlayback)
        {
            "establish"
                .x(() =>
                    {
                        inMemoryStorage = new InMemoryStorage();

                        realServiceWhileRecording = A.Fake<ILibraryService>();
                        realServiceDuringPlayback = A.Fake<ILibraryService>();

                        A.CallTo(() => realServiceWhileRecording.GetCount("9780345813923"))
                            .ReturnsNextFromSequence(11, 10);
                        A.CallTo(() => realServiceWhileRecording.GetCount("9781593078225"))
                            .Returns(3);
                    });

            "when self initializing a fake"
                .x(() =>
                    {
                        using (var recorder = new RecordingManager(inMemoryStorage))
                        {
                            var fakeService = A.Fake<ILibraryService>(options => options
                                .Wrapping(realServiceWhileRecording).RecordedBy(recorder));

                            count1ForBook1WhileRecording = fakeService.GetCount("9780345813923");
                            fakeService.GetCount("9781593078225");
                            fakeService.GetCount("9780345813923");
                        }

                        using (var recorder = new RecordingManager(inMemoryStorage))
                        {
                            var playbackFakeService = A.Fake<ILibraryService>(options => options
                                .Wrapping(realServiceDuringPlayback).RecordedBy(recorder));

                            count1ForBook1DuringPlayback = playbackFakeService.GetCount("9780345813923");
                            count1ForBook2DuringPlayback = playbackFakeService.GetCount("9781593078225");
                            count2ForBook1DuringPlayback = playbackFakeService.GetCount("9780345813923");
                        }
                    });

            "it should forward calls to the wrapped service while recording"
                .x(() => A.CallTo(() => realServiceWhileRecording.GetCount("9780345813923"))
                             .MustHaveHappened(Repeated.Exactly.Twice));

            "it should return the result while recording"
                .x(() => count1ForBook1WhileRecording.Should().Be(11));

            "it should not forward calls to the wrapped service during playback"
                .x(() => A.CallTo(realServiceDuringPlayback).MustNotHaveHappened());

            "it should return the recorded result for the first set of arguments"
                .x(() => count1ForBook1DuringPlayback.Should().Be(11));

            "it should return the recorded result for the second set of arguments"
                .x(() => count1ForBook2DuringPlayback.Should().Be(3));

            "it should return the second recorded result when arguments are repeated"
                .x(() => count2ForBook1DuringPlayback.Should().Be(10));
        }
        public static void SelfInitializingOutAndRef(
            InMemoryStorage inMemoryStorage,
            ILibraryService realServiceWhileRecording,
            ILibraryService realServiceDuringPlayback,
            int @out,
            int @ref)
        {
            "Given a call storage object"
                .x(() => inMemoryStorage = new InMemoryStorage());

            "And a real service to wrap while recording"
                .x(() =>
                {
                    realServiceWhileRecording = A.Fake<ILibraryService>();

                    int localOut;
                    int localRef = 0;
                    A.CallTo(() => realServiceWhileRecording.TryToSetSomeOutAndRefParameters(out localOut, ref localRef))
                        .WithAnyArguments()
                        .Returns(true)
                        .AssignsOutAndRefParameters(19, 8);
                });

            "And a real service to wrap while playing back"
                .x(() => realServiceDuringPlayback = A.Fake<ILibraryService>());

            "When I use a self-initialized fake in recording mode to try to set some out and ref parameters"
                .x(() =>
                {
                    using (var recorder = new RecordingManager(inMemoryStorage))
                    {
                        var fakeService = A.Fake<ILibraryService>(options => options
                            .Wrapping(realServiceWhileRecording).RecordedBy(recorder));

                        int localOut;
                        int localRef = 0;
                        fakeService.TryToSetSomeOutAndRefParameters(out localOut, ref localRef);
                    }
                });

            "And I use a self-initialized fake in playback mode to try to set some out and ref parameters"
                .x(() =>
                    {
                        using (var recorder = new RecordingManager(inMemoryStorage))
                        {
                            var playbackFakeService = A.Fake<ILibraryService>(options => options
                                .Wrapping(realServiceDuringPlayback).RecordedBy(recorder));

                            playbackFakeService.TryToSetSomeOutAndRefParameters(out @out, ref @ref);
                        }
                    });

            "Then the playback fake sets the out parameter to the value seen in recording mode"
                .x(() => @out.Should().Be(19));

            "And it sets the ref parameter to the value seen in recording mode"
                .x(() => @ref.Should().Be(8));
        }
        public static void SelfInitializingExceptionWhileRecording(
            InMemoryStorage inMemoryStorage,
            ILibraryService realServiceWhileRecording,
            ILibraryService realServiceDuringPlayback,
            Exception originalException,
            Exception exceptionWhileRecording,
            Exception exceptionWhilePlayingBack)
        {
            "Given a call storage object"
                .x(() => inMemoryStorage = new InMemoryStorage());

            "And a real service to wrap while recording"
                .x(() => realServiceWhileRecording = A.Fake<ILibraryService>());

            "And the real service throws an exception when getting the title for book 1"
                .x(() =>
                {
                    A.CallTo(() => realServiceWhileRecording.GetTitle("1"))
                        .Throws(originalException = new InvalidOperationException());
                });

            "And a real service to wrap while playing back"
                .x(() => realServiceDuringPlayback = A.Fake<ILibraryService>());

            "When I use a self-initialized fake in recording mode to get the title for book 1"
                .x(() =>
                {
                    using (var recorder = new RecordingManager(inMemoryStorage))
                    {
                        var fakeService = A.Fake<ILibraryService>(options => options
                            .Wrapping(realServiceWhileRecording).RecordedBy(recorder));

                        exceptionWhileRecording = Record.Exception(() => fakeService.GetTitle("1"));
                    }
                });

            "And I use a self-initialized fake in playback mode to get the title for book 1"
                .x(() =>
                {
                    using (var recorder = new RecordingManager(inMemoryStorage))
                    {
                        var fakeService = A.Fake<ILibraryService>(options => options
                            .Wrapping(realServiceDuringPlayback).RecordedBy(recorder));

                        exceptionWhilePlayingBack = Record.Exception(() => fakeService.GetTitle("1"));
                    }
                });

            "Then the recording fake throws the original exception"
                .x(() => exceptionWhileRecording.Should().BeSameAs(originalException));

            "But the playback fake throws a recording exception"
                .x(() => exceptionWhilePlayingBack.Should().BeAnExceptionOfType<RecordingException>());
        }
        public static void SelfInitializingThrowsIfTooManyCallsEncountered(
            InMemoryStorage inMemoryStorage,
            ILibraryService realServiceWhileRecording,
            ILibraryService realServiceDuringPlayback,
            Exception exception)
        {
            "Given a call storage object"
                .x(() => inMemoryStorage = new InMemoryStorage());

            "And a real service to wrap while recording"
                .x(() => realServiceWhileRecording = A.Fake<ILibraryService>());

            "And a real service to wrap while playing back"
                .x(() => realServiceDuringPlayback = A.Fake<ILibraryService>());

            "When I use a self-initialized fake in recording mode to get the count and title for book 1"
                .x(() =>
                {
                    using (var recorder = new RecordingManager(inMemoryStorage))
                    {
                        var fakeService = A.Fake<ILibraryService>(options => options
                            .Wrapping(realServiceWhileRecording).RecordedBy(recorder));

                        fakeService.GetCount("1");
                        fakeService.GetTitle("1");
                    }
                });

            "And I use a self-initialized fake in playback mode to get the count and title and count for book 1"
                .x(() =>
                {
                    using (var recorder = new RecordingManager(inMemoryStorage))
                    {
                        var playbackFakeService = A.Fake<ILibraryService>(options => options
                            .Wrapping(realServiceDuringPlayback).RecordedBy(recorder));

                        playbackFakeService.GetCount("1");
                        playbackFakeService.GetTitle("1");
                        exception = Record.Exception(() => playbackFakeService.GetCount("1"));
                    }
                });

            // This result demonstrates that the self-initialized fake relies on a script
            // defined by which methods are called, and is completely inflexible with
            // regard to the number of repetitions of the calls.
            "Then the playback fake throws a recording exception"
                .x(() => exception.Should().BeAnExceptionOfType<RecordingException>());
        }
        public static void SelfInitializing(
            InMemoryStorage inMemoryStorage,
            ILibraryService realServiceWhileRecording,
            ILibraryService realServiceDuringPlayback,
            IEnumerable<int> countsWhileRecording,
            IEnumerable<int> countsDuringPlayback)
        {
            "Given a call storage object"
                .x(() => inMemoryStorage = new InMemoryStorage());

            "And a real service to wrap while recording"
                .x(() =>
                {
                    realServiceWhileRecording = A.Fake<ILibraryService>();

                    A.CallTo(() => realServiceWhileRecording.GetCount("1"))
                        .ReturnsNextFromSequence(0x1A, 0x1B);
                    A.CallTo(() => realServiceWhileRecording.GetCount("2"))
                        .Returns(0x2);
                });

            "And a real service to wrap while playing back"
                .x(() => realServiceDuringPlayback = A.Fake<ILibraryService>());

            "When I use a self-initialized fake in recording mode to get the counts for book 1, 2, and 1 again"
                .x(() =>
                    {
                        using (var recorder = new RecordingManager(inMemoryStorage))
                        {
                            var fakeService = A.Fake<ILibraryService>(options => options
                                .Wrapping(realServiceWhileRecording).RecordedBy(recorder));

                            countsWhileRecording = new List<int>
                            {
                                fakeService.GetCount("1"),
                                fakeService.GetCount("2"),
                                fakeService.GetCount("1")
                            };
                        }
                    });

            "And I use a self-initialized fake in playback mode to get the counts for book 1, 2, and 1 again"
                .x(() =>
                    {
                        using (var recorder = new RecordingManager(inMemoryStorage))
                        {
                            var playbackFakeService = A.Fake<ILibraryService>(options => options
                                .Wrapping(realServiceDuringPlayback).RecordedBy(recorder));

                            countsDuringPlayback = new List<int>
                            {
                                playbackFakeService.GetCount("1"),
                                playbackFakeService.GetCount("2"),
                                playbackFakeService.GetCount("1")
                            };
                        }
                    });

            "Then the recording fake forwards calls to the wrapped service"
                .x(() => A.CallTo(() => realServiceWhileRecording.GetCount("1"))
                    .MustHaveHappened(Repeated.Exactly.Twice));

            "And the recording fake returns the wrapped service's results"
                .x(() => countsWhileRecording.Should().Equal(0x1A, 0x2, 0x1B));

            "And the playback fake does not forward calls to the wrapped service"
                .x(() => A.CallTo(realServiceDuringPlayback).MustNotHaveHappened());

            "And the playback fake returns the recorded results"
                .x(() => countsDuringPlayback.Should().Equal(0x1A, 0x2, 0x1B));
        }
        public static void SelfInitializingIgnoresParameterValues(
            InMemoryStorage inMemoryStorage,
            ILibraryService realServiceWhileRecording,
            ILibraryService realServiceDuringPlayback,
            IEnumerable<int> countsWhileRecording,
            IEnumerable<int> countsDuringPlayback)
        {
            "Given a call storage object"
                .x(() => inMemoryStorage = new InMemoryStorage());

            "And a real service to wrap while recording"
                .x(() =>
                {
                    realServiceWhileRecording = A.Fake<ILibraryService>();

                    A.CallTo(() => realServiceWhileRecording.GetCount("1"))
                        .Returns(0x1);
                    A.CallTo(() => realServiceWhileRecording.GetCount("2"))
                        .Returns(0x2);
                });

            "And a real service to wrap while playing back"
                .x(() => realServiceDuringPlayback = A.Fake<ILibraryService>());

            "When I use a self-initialized fake in recording mode to get the counts for book 2 and 1"
                .x(() =>
                {
                    using (var recorder = new RecordingManager(inMemoryStorage))
                    {
                        var fakeService = A.Fake<ILibraryService>(options => options
                            .Wrapping(realServiceWhileRecording).RecordedBy(recorder));

                        countsWhileRecording = new List<int>
                            {
                                fakeService.GetCount("2"),
                                fakeService.GetCount("1")
                            };
                    }
                });

            "And I use a self-initialized fake in playback mode to get the counts for book 1 and 2"
                .x(() =>
                {
                    using (var recorder = new RecordingManager(inMemoryStorage))
                    {
                        var playbackFakeService = A.Fake<ILibraryService>(options => options
                            .Wrapping(realServiceDuringPlayback).RecordedBy(recorder));

                        countsDuringPlayback = new List<int>
                            {
                                playbackFakeService.GetCount("1"),
                                playbackFakeService.GetCount("2"),
                            };
                    }
                });

            "Then the recording fake returns the wrapped service's results"
                .x(() => countsWhileRecording.Should().Equal(0x2, 0x1));

            // These results demonstrate that the self-initialized fake relies on a script
            // defined by which methods are called, without regard to the arguments
            // passed to the methods.
            "And the playback fake returns results in 'recorded order'"
                .x(() => countsDuringPlayback.Should().Equal(0x2, 0x1));
        }