public void SingleTypedExchangeActorInheritanceTest()
        {
            var msgCount1 = 0;
            var msgCount2 = 0;

            using (var waitHandle = new AutoResetEvent(false))
            {
                var actorMock1 = new Mock <IActor>();
                actorMock1.Setup(a => a.CanReceive).Returns(true);
                actorMock1.Setup(a => a.ReceiveTarget).Returns(msg =>
                {
                    output.WriteLine($"Message received by {msg.Recipient.Name}: {msg.Message} from {msg.Sender.Name}");
                    msgCount1++;
                    // ReSharper disable once AccessToDisposedClosure
                    if (msg.Message.ToString().StartsWith("END"))
                    {
                        waitHandle.Set();
                    }
                    return(true);
                });
                var actorMock2 = new Mock <IActor>();
                actorMock2.Setup(a => a.CanReceive).Returns(true);
                actorMock2.Setup(a => a.ReceiveTarget).Returns(msg =>
                {
                    output.WriteLine($"Message received by {msg.Recipient.Name}: {msg.Message} from {msg.Sender.Name}");
                    msgCount2++;
                    return(true);
                });

                using (var actorSystem = new ActorSystem(ActorSystemOptions.Default))
                {
                    //execute
                    using (var actorExch = new TypedSingleExchangeActor(actorSystem, "EX"))
                    {
                        var actorRefExch = actorExch.Self;

                        var actorRef1 = actorSystem.RegisterActor(actorMock1.Object, "tst actor1");
                        var actorRef2 = actorSystem.RegisterActor(actorMock2.Object, "tst actor2");

                        actorRefExch.Tell("TST1", ActorRefs.Empty);                                                 //drop
                        actorRefExch.Tell(new SubscriptionMessage(), actorRef1);                                    //drop - wrong type of subscription message
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(NullReferenceException)), actorRef1); //a1: NPE; a2: N/A
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(Exception)), actorRef2);              //a1: NPE; a2: E
                        actorRefExch.Tell(new NullReferenceException("TST2"), ActorRefs.Empty);                     //a1
                        actorRefExch.Tell(new InvalidOperationException("TST3"), ActorRefs.Empty);                  //a2
                        actorRefExch.Tell(4, ActorRefs.Empty);                                                      //drop
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(object)), actorRef1);                 //a1: NPE, obj; a2: E
                        actorRefExch.Tell(5, ActorRefs.Empty);                                                      //a1
                        actorRefExch.Tell(new Exception("TST6"), ActorRefs.Empty);                                  //a2 - exact match
                        actorRefExch.Tell(new TypedUnSubscriptionMessage(typeof(Exception)), actorRef2);            //a1: NPE, obj; a2: N/A
                        actorRefExch.Tell(new Exception("TST7"), ActorRefs.Empty);                                  //a1 - fallback
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(Exception)), actorRef2);              //a1: NPE, obj; a2: E
                        actorRefExch.Tell(new InvalidOperationException("TST8"), ActorRefs.Empty);                  //a1 - fallback (object registered first)
                        actorRefExch.Tell(new TypedUnSubscriptionMessage(typeof(object)), actorRef1);               //a1: NPE; a2: E
                        actorRefExch.Tell(new InvalidOperationException("TST9"), ActorRefs.Empty);                  //a2 - fallback
                        actorRefExch.Tell(new NullReferenceException("TST10"), ActorRefs.Empty);                    //a1
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(string)), actorRef1);                 //a1: NPE,str; a2: E
                        actorRefExch.Tell("END", ActorRefs.Empty);                                                  //a1, finish

                        if (!waitHandle.WaitOne(2000, false))
                        {
                            output.WriteLine("ERR: Message receive timeout");
                            Assert.True(false, "Timeout");
                        }
                    }

                    //check
                    msgCount1.Should().Be(6);
                    msgCount2.Should().Be(3);
                    actorSystem.DeadLetters.Count.Should().Be(3);
                    actorSystem.ErrorMessageQueue.Count.Should().Be(0);
                }
            }
        }
        public void SingleTypedExchangeActorTest()
        {
            var msgCount1 = 0;
            var msgCount2 = 0;

            using (var waitHandle = new AutoResetEvent(false))
            {
                var actorMock1 = new Mock <IActor>();
                actorMock1.Setup(a => a.CanReceive).Returns(true);
                actorMock1.Setup(a => a.ReceiveTarget).Returns(msg =>
                {
                    output.WriteLine($"Message received by {msg.Recipient.Name}: {msg.Message} from {msg.Sender.Name}");
                    msgCount1++;
                    // ReSharper disable once AccessToDisposedClosure
                    if (msg.Message.ToString().StartsWith("END"))
                    {
                        waitHandle.Set();
                    }
                    return(true);
                });
                var actorMock2 = new Mock <IActor>();
                actorMock2.Setup(a => a.CanReceive).Returns(true);
                actorMock2.Setup(a => a.ReceiveTarget).Returns(msg =>
                {
                    output.WriteLine($"Message received by {msg.Recipient.Name}: {msg.Message} from {msg.Sender.Name}");
                    msgCount2++;
                    return(true);
                });

                using (var actorSystem = new ActorSystem(ActorSystemOptions.Default))
                {
                    //execute
                    using (var actorExch = new TypedSingleExchangeActor(actorSystem, "EX"))
                    {
                        var actorRefExch = actorExch.Self;

                        var actorRef1 = actorSystem.RegisterActor(actorMock1.Object, "tst actor1");
                        var actorRef2 = actorSystem.RegisterActor(actorMock2.Object, "tst actor2");

                        actorRefExch.Tell("TST1", ActorRefs.Empty);                                   //drop
                        actorRefExch.Tell(new SubscriptionMessage(), actorRef1);                      //drop - wrong type of subscription message
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(string)), actorRef1);   //string -> a1
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(int)), actorRef2);      //int to -> a2
                        actorRefExch.Tell("TST2", ActorRefs.Empty);                                   //a1
                        actorRefExch.Tell("TST3", ActorRefs.Empty);                                   //a1
                        actorRefExch.Tell(4, ActorRefs.Empty);                                        //a2
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(string)), actorRef2);   //string -> a2
                        actorRefExch.Tell("TST5", ActorRefs.Empty);                                   //a2
                        actorRefExch.Tell(new TypedUnSubscriptionMessage(typeof(string)), actorRef1); //ignore
                        actorRefExch.Tell("TST6", ActorRefs.Empty);                                   //a2
                        actorRefExch.Tell(new TypedUnSubscriptionMessage(typeof(string)), actorRef2); //string ->drop
                        actorRefExch.Tell("TST7", ActorRefs.Empty);                                   //drop
                        actorRefExch.Tell(8, ActorRefs.Empty);                                        //a2
                        actorRefExch.Tell(9.0, ActorRefs.Empty);                                      //drop
                        actorRefExch.Tell(new TypedSubscriptionMessage(typeof(string)), actorRef1);   //subscribe again
                        actorRefExch.Tell("END", ActorRefs.Empty);                                    //a1, finish

                        if (!waitHandle.WaitOne(3000, false))
                        {
                            output.WriteLine("ERR: Message receive timeout");
                            Assert.True(false, "Timeout");
                        }
                    }

                    //check
                    msgCount1.Should().Be(3);
                    msgCount2.Should().Be(4);
                    actorSystem.DeadLetters.Count.Should().Be(4);
                    actorSystem.ErrorMessageQueue.Count.Should().Be(0);
                }
            }
        }