public void Interpreter_error_handling_should_fail_when_OnPull_throws()
        {
            var stage = new RestartTestStage(onPull: (stg, context) =>
            {
                if (stg.Sum < 0)
                {
                    throw TE();
                }
                return(null);
            });

            WithOneBoundedSetup(new IStage <int, int>[] {
                new Select <int, int>(x => x + 1, resumingDecider),
                stage,
                new Select <int, int>(x => x + 100, resumingDecider)
            },
                                (lastEvents, upstream, downstream) =>
            {
                downstream.RequestOne();
                lastEvents().Should().BeEquivalentTo(new RequestOne());
                upstream.OnNext(2);
                lastEvents().Should().BeEquivalentTo(new OnNext(103));

                downstream.RequestOne();
                lastEvents().Should().BeEquivalentTo(new RequestOne());
                upstream.OnNext(-5);     // this will trigger failure of next requestOne (pull)
                lastEvents().Should().BeEquivalentTo(new OnNext(99));

                downstream.RequestOne();     // boom
                lastEvents().Should().BeEquivalentTo(new OnError(TE()), new Cancel());
            });
        }
        public void Interpreter_error_handling_should_restart_when_OnPush_throws()
        {
            var stage = new RestartTestStage(onPush: (_, element, context) =>
            {
                if (element <= 0)
                {
                    throw TE();
                }
                return(null);
            });

            WithOneBoundedSetup(new IStage <int, int>[] {
                new Select <int, int>(x => x + 1, resumingDecider),
                stage,
                new Select <int, int>(x => x + 100, resumingDecider)
            },
                                (lastEvents, upstream, downstream) =>
            {
                downstream.RequestOne();
                lastEvents().Should().BeEquivalentTo(new RequestOne());
                upstream.OnNext(2);
                lastEvents().Should().BeEquivalentTo(new OnNext(103));

                downstream.RequestOne();
                lastEvents().Should().BeEquivalentTo(new RequestOne());
                upstream.OnNext(-1);     // boom
                lastEvents().Should().BeEquivalentTo(new RequestOne());

                upstream.OnNext(3);
                lastEvents().Should().BeEquivalentTo(new OnNext(104));
            });
        }
        public void Interpreter_error_handling_should_restart_when_OnPush_throws_after_context_Push()
        {
            var stage = new RestartTestStage(onPush: (_, element, context) =>
            {
                var result = context.Push(element);
                if (element <= 0)
                {
                    throw TE();
                }
                return(result);
            });

            WithOneBoundedSetup(new IStage <int, int>[] {
                new Select <int, int>(x => x + 1, resumingDecider),
                stage,
                new Select <int, int>(x => x + 100, resumingDecider)
            },
                                (lastEvents, upstream, downstream) =>
            {
                downstream.RequestOne();
                lastEvents().Should().BeEquivalentTo(new RequestOne());
                upstream.OnNext(2);
                lastEvents().Should().BeEquivalentTo(new OnNext(103));

                downstream.RequestOne();
                lastEvents().Should().BeEquivalentTo(new RequestOne());
                upstream.OnNext(-1);     // boom
                // The element has been pushed before the exception, there is no way back
                lastEvents().Should().BeEquivalentTo(new OnNext(100));

                downstream.RequestOne();
                lastEvents().Should().BeEquivalentTo(new RequestOne());

                upstream.OnNext(3);
                lastEvents().Should().BeEquivalentTo(new OnNext(104));
            });
        }