public ActorContextTest()
 {
     _ActorContext = new ActorContext();
     var factory = new ActorFactory();
     _Proxified = new DummyClass();
     _Interface = factory.Build<IDummyInterface2>(_Proxified);
 }
        public async Task Method_Should_Run_On_Same_Thread_After_Await()
        {
            var target = new DummyClass();
            var intface = _Factory.Build<IDummyInterface2>(target);


            var res = await intface.DoAnRedoAsync();

            res.Item1.Should().Be(res.Item2);
        }
        public async Task Method_Should_Run_On_Separated_Thread()
        {
            var current = Thread.CurrentThread;
            var target = new DummyClass();
            var intface = _Factory.Build<IDummyInterface2>(target);
            await intface.DoAsync();

            target.Done.Should().BeTrue();
            target.CallingThread.Should().NotBeNull();
            target.CallingThread.Should().NotBe(current);
        }
        public async Task BuildAsync_Should_Call_Constructor_On_Actor_Thread()
        {
            var current = Thread.CurrentThread;
            DummyClass target = null;
            IDummyInterface2 intface = await _Factory.BuildAsync<IDummyInterface2>(() => { target = new DummyClass(); return target; });
            await intface.DoAsync();

            target.Done.Should().BeTrue();
            target.CallingConstructorThread.Should().NotBe(current);
            target.CallingConstructorThread.Should().Be(target.CallingThread);
        }
        public async Task Method_WithAReturn_Should_Run_On_Separated_Pooled_Thread()
        {
            var current = Thread.CurrentThread;
            var target = new DummyClass();
            var intface = _TaskPoolActorFactory.Build<IDummyInterface2>(target);
            var res = await intface.ComputeAsync(2);

            res.Should().Be(2);
            target.CallingThread.Should().NotBeNull();
            target.CallingThread.IsThreadPoolThread.Should().BeTrue();
            target.CallingThread.Should().NotBe(current);
        }
        public async Task Proxy_Method_WithoutResult_Should_Dispatch_On_Captured_UI_Thread()
        {
            //arrange
            var obj = new DummyClass();
            var actor = _Factory.Build<IDummyInterface2>(obj);

            //act
            await actor.DoAsync();

            //assert
            obj.CallingThread.Should().Be(_UIMessageLoop.UIThread);
        }
        public async Task Proxy_Method_WithoutResult_Should_Be_Called()
        {
            //arrange
            var obj = new DummyClass();
            var actor = _Factory.Build<IDummyInterface2>(obj);

            //act
            await actor.DoAsync();

            //assert
            obj.Done.Should().BeTrue();
        }
        public async Task Method_Should_Always_Run_On_Same_Thread()
        {
            var target = new DummyClass();
            var intface = _Factory.Build<IDummyInterface2>(target);
            await intface.DoAsync();

            var thread = target.CallingThread;

            await intface.DoAsync();

            target.CallingThread.Should().Be(thread);
        }
        public async Task Method_Should_Not_Always_OnPoolThread()
        {
            var current = Thread.CurrentThread;
            var target = new DummyClass();
            var intface = _TaskPoolActorFactory.Build<IDummyInterface2>(target);
            await intface.DoAsync();

            var thread = target.CallingThread;

            await intface.DoAsync();
            target.CallingThread.IsThreadPoolThread.Should().BeTrue();
            target.CallingThread.Should().NotBe(current);
        }
        public async Task Proxy_Method_WithResult_Should_Called()
        {
            //arrange
            var obj = new DummyClass();
            var actor = _Factory.Build<IDummyInterface2>(obj);

            //act
            var res = await actor.ComputeAsync(5);

            //assert
            obj.Done.Should().BeTrue();
            res.Should().Be(5);
        }
        public async Task Abort_Should_Kill_Thread()
        {
            //arrange
            var target1 = new DummyClass();
            var intface1 = _Factory.Build<IDummyInterface2>(target1);

            //act
            await intface1.DoAsync();

            //assert
            await _Factory.Abort();
            target1.CallingThread.IsAlive.Should().BeFalse();
        }
        public async Task Each_Actor_Should_Run_On_Separated_Thread()
        {
            //arrange
            var target1 = new DummyClass();
            var target2 = new DummyClass();
            var intface1 = _TaskPoolActorFactory.Build<IDummyInterface2>(target1);
            var intface2 = _TaskPoolActorFactory.Build<IDummyInterface2>(target2);

            //act
            await Task.WhenAll(intface1.SlowDoAsync(), intface2.SlowDoAsync());

            //assert
            target1.CallingThread.Should().NotBe(target2.CallingThread);
        }
        public async Task Each_Actor_Should_Run_On_Separated_Thread_When_Shared_Thread_Is_False()
        {
            //arrange
            var target1 = new DummyClass();
            var target2 = new DummyClass();
            var intface1 = _Factory.Build<IDummyInterface2>(target1);
            var intface2 = _Factory.Build<IDummyInterface2>(target2);

            //act
            await intface1.DoAsync();
            await intface2.DoAsync();

            //assert
            target1.CallingThread.Should().NotBe(target2.CallingThread);
        }
        public async Task All_Actors_Should_Run_On_Same_Thread()
        {
            //arrange
            var target1 = new DummyClass();
            var target2 = new DummyClass();
            var intface1 = _Factory.Build<IDummyInterface2>(target1);
            var intface2 = _Factory.Build<IDummyInterface2>(target2);

            //act
            await intface1.DoAsync();
            await intface2.DoAsync();

            //assert
            target1.CallingThread.Should().Be(target2.CallingThread);
        }
        public async Task TaskFactory_Should_Return_TaskFactory_Compatible_With_Proxy_Thread_SynchronizationContextFactory_Context()
        {
            //arrange
            var UIMessageLoop = new WPFThreadingHelper();
            UIMessageLoop.Start().Wait();

            var scf = UIMessageLoop.Dispatcher.Invoke(() => new SynchronizationContextFactory());

            _Proxified = new DummyClass();
            _Interface = scf.Build<IDummyInterface2>(_Proxified);

            //act
            var res = _ActorContext.GetTaskFactory(_Proxified);
            Thread tfthread = await res.StartNew(() => Thread.CurrentThread);

            //assert
            tfthread.Should().Be(UIMessageLoop.UIThread);

            UIMessageLoop.Stop();
        }
        public void Build_Should_Throw_Exception_IsSamePOCO_HasBeenUsedWithOtherFactory()
        {
            var target = new DummyClass();
            var sharedFactory = new SharedThreadActorFactory();
            var intface = sharedFactory.Build<IDummyInterface2>(target);


            Action Do = () => _Factory.Build<IDummyInterface2>(target);

            Do.ShouldThrow<ArgumentException>().And.Message.Should().Contain("Shared");
        }
        public void Build_Should_CreateSameInterface_ForSamePOCO()
        {
            var target = new DummyClass();
            var intface = _Factory.Build<IDummyInterface2>(target);
            var intface2 = _Factory.Build<IDummyInterface2>(target);

            intface.Should().BeSameAs(intface2);
        }
        public async Task Actor_IActorLifeCycle_Abort_Should_Cancel_Actor_Thread()
        {

            //arrange
            var clas = new DummyClass();
            var intface = _Factory.Build<IDummyInterface2>(clas);

            await intface.DoAsync();
            //act
            IActorCompleteLifeCycle disp = intface as IActorCompleteLifeCycle;

            await disp.Abort();

            //assert
            clas.CallingThread.IsAlive.Should().BeFalse();
        }
        public async Task Task_returned_By_Method_Should_Be_Awaited()
        {
            var target = new DummyClass();
            var intface = _Factory.Build<IDummyInterface2>(target);
            await intface.SlowDoAsync();

            target.Done.Should().BeTrue();
        }
        public void GetTaskScheduler_Should_Return_SynchronizationContext_Compatible_With_Proxy_Thread_SynchronizationContextFactory_Context()
        {
            //arrange
            var UIMessageLoop = new WPFThreadingHelper();
            UIMessageLoop.Start().Wait();

            var scf = UIMessageLoop.Dispatcher.Invoke(() => new SynchronizationContextFactory());

            _Proxified = new DummyClass();
            _Interface = scf.Build<IDummyInterface2>(_Proxified);

            //act
            var res = _ActorContext.GetTaskScheduler(_Proxified);
            var uisc = UIMessageLoop.Dispatcher.Invoke(()=>  SynchronizationContext.Current);
         

            //assert
            res.Should().NotBeNull();
            res.Should().BeOfType<SynchronizationContextTaskScheduler>();
            var ressync = res as SynchronizationContextTaskScheduler;
            ressync.SynchronizationContext.Should().BeOfType(uisc.GetType());

            UIMessageLoop.Stop();
        }