public void Engine_Subject_Dispose()
        {
            var id  = new Uri("tests://bar/foo");
            var svc = new MiniService();
            var sch = new MiniScheduler();

            var subject = GetSubject(id, svc);

            var o = subject.CreateObserver();

            var xs = new List <int>();

            var s1 = subject.Subscribe(Observer.Create <int>(xs.Add, _ => { }, () => { }));

            new SubscriptionInitializeVisitor(s1).Initialize(CreateOperatorContext(new Uri("tests://qux/1"), svc, sch));

            var s2 = subject.Subscribe(Observer.Create <int>(xs.Add, _ => { }, () => { }));

            new SubscriptionInitializeVisitor(s2).Initialize(CreateOperatorContext(new Uri("tests://qux/2"), svc, sch));

            o.OnNext(42);

            subject.Dispose();

            o.OnNext(43);                                     // does not throw; by design

            var s3 = subject.Subscribe(Observer.Nop <int>()); // does not throw; by design

            o.OnNext(44);                                     // does not throw; by design

            Assert.ThrowsException <ObjectDisposedException>(() =>
            {
                new SubscriptionInitializeVisitor(s3).Initialize(CreateOperatorContext(new Uri("tests://qux/3"), svc, sch));
            });
        }
        private static InnerSubject <int> GetSubject(Uri id, MiniService svc)
        {
            var sch = new MiniScheduler();
            var ctx = CreateOperatorContext(id, svc, sch);

            var subject = new InnerSubject <int>();

            subject.SetContext(ctx);
            subject.Start();

            return(subject);
        }
        public void Engine_Subject_Checkpoint_SealLater()
        {
            var id  = new Uri("tests://bar/foo");
            var svc = new MiniService();
            var sch = new MiniScheduler();

            var mosc1 = new MockOperatorStateContainer();
            var mosc2 = new MockOperatorStateContainer();

            {
                var subject = GetSubject(id, svc);

                var xs = (ISubscribable <int>)subject;

                var d1 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d1).Initialize(CreateOperatorContext(new Uri("tests://qux/1"), svc, sch));

                var d2 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d2).Initialize(CreateOperatorContext(new Uri("tests://qux/2"), svc, sch));

                d1.Dispose();

                var d3 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d3).Initialize(CreateOperatorContext(new Uri("tests://qux/3"), svc, sch));

                Assert.IsTrue(subject.StateChanged);

                using (var oswf = mosc1.CreateWriter())
                {
                    oswf.SaveState(subject);
                }

                Assert.IsTrue(subject.StateChanged);

                subject.OnStateSaved();

                Assert.IsFalse(subject.StateChanged);
            }

            {
                var subject = GetSubject(id, svc);

                Assert.IsTrue(subject.StateChanged);

                using (var osrf = mosc1.CreateReader())
                {
                    osrf.LoadState(subject);
                }

                Assert.IsFalse(subject.StateChanged);

                var xs = (ISubscribable <int>)subject;

                var d2 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d2).Initialize(CreateOperatorContext(new Uri("tests://qux/2"), svc, sch));

                var d3 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d3).Initialize(CreateOperatorContext(new Uri("tests://qux/3"), svc, sch));

                Assert.IsFalse(subject.StateChanged);

                var d4 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d4).Initialize(CreateOperatorContext(new Uri("tests://qux/4"), svc, sch));

                Assert.IsTrue(subject.StateChanged);

                var d5 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d5).Initialize(CreateOperatorContext(new Uri("tests://qux/5"), svc, sch));

                d3.Dispose();

                subject.Seal();

                Assert.IsTrue(subject.StateChanged);

                using (var oswf = mosc2.CreateWriter())
                {
                    oswf.SaveState(subject);
                }

                Assert.IsTrue(subject.StateChanged);

                subject.OnStateSaved();

                Assert.IsFalse(subject.StateChanged);
            }

            {
                var subject = GetSubject(id, svc);

                Assert.IsTrue(subject.StateChanged);

                using (var osrf = mosc2.CreateReader())
                {
                    osrf.LoadState(subject);
                }

                Assert.IsFalse(subject.StateChanged);

                var xs = (ISubscribable <int>)subject;

                var d2 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d2).Initialize(CreateOperatorContext(new Uri("tests://qux/2"), svc, sch));

                var d4 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d4).Initialize(CreateOperatorContext(new Uri("tests://qux/4"), svc, sch));

                var d5 = xs.Subscribe(Observer.Nop <int>());
                new SubscriptionInitializeVisitor(d5).Initialize(CreateOperatorContext(new Uri("tests://qux/5"), svc, sch));

                Assert.IsFalse(subject.StateChanged);

                // gets sealed after all subscriptions have been recreated
                Assert.ThrowsException <InvalidOperationException>(() => subject.Subscribe(Observer.Nop <int>()));
            }
        }