Beispiel #1
0
        public static void ShutdownRequest_AfterShuttingDown()
        {
            // can not enqueue after shutting down event was enqueued
            var queue = new ManualEventQueue();

            Assert.True(queue.BeginShutdown());
            Assert.False(queue.Enqueue(new ShutdownRequestEvent()));

            // handling is skipped, if a shutting down event is enqueued beforehand
            queue = new ManualEventQueue();

            bool requestDetected = false;

            queue.Subscribers.Add(
                DelegateEventHandler.OnShutdownRequest(
                    e => requestDetected = true),
                weakRef: false);

            Assert.True(queue.Enqueue(new ShutdownRequestEvent())); // enqueueing succeeds
            Assert.True(queue.Enqueue(new ShuttingDownEvent()));    // shutting down event added
            Assert.False(requestDetected);
            Assert.True(queue.HandleNext());                        // the request was "handled" successfully
            Assert.False(requestDetected);                          // but the handler was not actually invoked

            // ensure there are no unexpected events in the queue, that could have shifted the position of the request event
            Assert.True(queue.HandleNext()); // shutting down event
            Assert.True(queue.HandleNext()); // shut down event
            Assert.False(queue.HandleNext());
            Assert.True(queue.IsShutDown);
        }
Beispiel #2
0
        public static void Callback()
        {
            var  queue   = new ManualEventQueue();
            var  evnt    = new TestEvent();
            bool handled = false;

            queue.Enqueue(
                evnt,
                onHandled: e =>
            {
                Assert.True(ReferenceEquals(e, evnt));
                handled = true;
            });

            // handled original event
            Assert.False(handled);
            Assert.True(queue.HandleNext());
            Assert.False(handled);

            // handle second event, implicitly added
            Assert.True(queue.HandleNext());
            Assert.True(handled);

            // no other events were added
            Assert.False(queue.HandleNext());
        }
Beispiel #3
0
        public static void EnqueueReturnValue()
        {
            var queue = new ManualEventQueue();
            var evnt  = new TestEvent();

            Assert.True(queue.Enqueue(evnt));

            // adding the same event a second time
            Assert.False(queue.Enqueue(evnt));

            // handling it and adding it again is fine however
            Assert.True(queue.HandleNext());
            Assert.False(queue.HandleNext()); // verify that we only added it once
            Assert.True(queue.Enqueue(evnt));

            // adding suspension
            queue.EventAdding.Suspend();
            Assert.False(queue.Enqueue(new TestEvent()));
            queue.EventAdding.Resume();
            Assert.True(queue.Enqueue(new TestEvent()));

            // handle all events
            while (queue.HandleNext())
            {
                ;
            }

            // add and handle shutting down event
            Assert.True(queue.Enqueue(new ShuttingDownEvent()));
            Assert.False(queue.Enqueue(new ShuttingDownEvent())); // another shutting down event is already enqueued
            Assert.True(queue.HandleNext());
            Assert.False(queue.Enqueue(new TestEvent()));         // no more events of any kind can be added
        }
Beispiel #4
0
        private static void ChangeToNeighboringState(ManualEventQueue manualQueue)   // Running --> Suspended
        {
            AppStateChangedEvent.Critical criticalEvent = null;
            var subscriber = DelegateEventHandler.On <AppStateChangedEvent.Critical>(
                e =>
            {
                criticalEvent = e;
            });

            TestApp.MainEventQueue.Subscribers.Add(subscriber);

            // immediately changes state, using a critical event
            TestApp.MoveToState(AppState.Suspended);
            Assert.AreEqual(AppState.Suspended, TestApp.CurrentState);
            Assert.NotNull(criticalEvent);
            Assert.AreEqual(AppState.Running, criticalEvent.OldState);
            Assert.AreEqual(AppState.Suspended, criticalEvent.NewState);

            // followed by a regular event
            Assert.True(manualQueue.HandleNext(out var evnt));
            var regularEvent = (AppStateChangedEvent.Regular)evnt;

            Assert.AreEqual(AppState.Suspended, regularEvent.CurrentState);

            TestApp.MainEventQueue.Subscribers.Remove(subscriber);
        }
Beispiel #5
0
        public static void HandleSupportsEventInheritance()
        {
            var queue      = new ManualEventQueue();
            var subscriber = new AncestorEventHandler();

            queue.Subscribers.AddAll(subscriber);

            // subscriber does not handle events not in it's inheritance tree
            Assert.True(queue.Enqueue(new TestEvent()));
            Assert.True(queue.HandleNext());
            Assert.Null(subscriber.LastEventHandled);

            // subscriber accepts event type it explicitly stated it would handle
            var namedEvent = new NamedEvent("name");

            Assert.True(queue.Enqueue(namedEvent));
            Assert.True(queue.HandleNext());
            Assert.AreSame(namedEvent, subscriber.LastEventHandled);

            // subscriber accepts event that inherit what it declared it would handle
            var derivedEvent = new DescendantEvent();

            Assert.True(queue.Enqueue(derivedEvent));
            Assert.True(queue.HandleNext());
            Assert.AreSame(derivedEvent, subscriber.LastEventHandled);
        }
Beispiel #6
0
        public static void StatelessHandler()
        {
            var queue = new ManualEventQueue();

            // create subscriber
            TestEvent lastEventHandled = null;
            var       subscriber       = DelegateEventHandler.On <TestEvent>(evnt => lastEventHandled = evnt);

            queue.Subscribers.Add(subscriber);

            // enqueue and handle event
            queue.Enqueue(new TestEvent()
            {
                Value = 3
            });
            Assert.Null(lastEventHandled);
            Assert.True(queue.HandleNext());

            // test subscriber
            Assert.NotNull(lastEventHandled);
            Assert.AreEqual(3, lastEventHandled.Value);

            // queue is empty again (no unhandled exceptions or anything else)
            Assert.False(queue.HandleNext());
        }
Beispiel #7
0
        public static void IsShutDown()
        {
            // initially open
            var queue = new ManualEventQueue();

            Assert.False(queue.IsShutDown);

            // removing all subscribers does not shut down the queue
            queue.Subscribers.AddAll(new TestEventHandler(), weakRef: false);
            queue.Subscribers.Clear();
            Assert.False(queue.IsShutDown);

            // adding the shutting down event is not enough
            queue.BeginShutdown();
            Assert.False(queue.IsShutDown);

            // handling the shutting down event is not enough...
            queue.Subscribers.Add(
                DelegateEventHandler.OnShuttingDown(
                    e => queue.Enqueue(new NamedEvent("shutting down event handler"))),
                weakRef: false);
            Assert.True(queue.HandleNext());
            Assert.False(queue.IsShutDown);

            // handling the NamedEvent added in the ShuttingDownEvent handler, is not enough
            Assert.True(queue.HandleNext());
            Assert.False(queue.IsShutDown);

            // ... but handling the ShutDownEvent is
            Assert.True(queue.HandleNext());
            Assert.True(queue.IsShutDown);
            Assert.False(queue.HandleNext());
        }
Beispiel #8
0
        private static void ChangeToNonNeighboringState(ManualEventQueue manualQueue)   // Shutdown --> Running
        {
            var criticalEvents = new List <AppStateChangedEvent.Critical>();
            var subscriber     = DelegateEventHandler.On <AppStateChangedEvent.Critical>(
                e => criticalEvents.Add(e));

            TestApp.MainEventQueue.Subscribers.Add(subscriber);

            // immediately changes state
            TestApp.MoveToState(AppState.Running);
            Assert.AreEqual(AppState.Running, TestApp.CurrentState);

            // critical events already handled
            Assert.AreEqual(2, criticalEvents.Count);

            var criticalEvent = criticalEvents[0];

            Assert.AreEqual(AppState.Shutdown, criticalEvent.OldState);
            Assert.AreEqual(AppState.Suspended, criticalEvent.NewState);

            criticalEvent = criticalEvents[1];
            Assert.AreEqual(AppState.Suspended, criticalEvent.OldState);
            Assert.AreEqual(AppState.Running, criticalEvent.NewState);

            // followed by a regular event
            Assert.True(manualQueue.HandleNext(out var evnt));
            var regularEvent = (AppStateChangedEvent.Regular)evnt;

            Assert.AreEqual(AppState.Running, regularEvent.CurrentState);

            TestApp.MainEventQueue.Subscribers.Remove(subscriber);
        }
Beispiel #9
0
        private static void Constructor(out ManualEventQueue queue)
        {
            // try to pass a null event queue
            Assert.Throws <ArgumentNullException>(() => TestApp.Initialize(null));

            // try to pass an event queue that's already shut down
            var manualQueue = new ManualEventQueue();

            manualQueue.BeginShutdown();
            while (manualQueue.HandleNext())
            {
                ;
            }
            Assert.Throws <ArgumentException>(() => TestApp.Initialize(manualQueue));

            // pass a proper event queue
            manualQueue = new ManualEventQueue();
            TestApp.Initialize(manualQueue);

            Assert.NotNull(AppBase.MainEventQueue);
            Assert.AreSame(manualQueue, AppBase.MainEventQueue.BaseEventQueue);
            Assert.AreSame(manualQueue.Subscribers, AppBase.MainEventQueue.Subscribers);
            Assert.AreSame(manualQueue.EventAdding, AppBase.MainEventQueue.EventAdding);
            Assert.AreSame(manualQueue.EventHandling, AppBase.MainEventQueue.EventHandling);
            Assert.AreSame(manualQueue.RaiseUnhandledEvents, AppBase.MainEventQueue.RaiseUnhandledEvents);
            Assert.AreEqual(AppState.Shutdown, AppBase.CurrentState);

            queue = manualQueue;
        }
Beispiel #10
0
        public static void NullCallback()
        {
            var queue = new ManualEventQueue();

            Assert.True(queue.Enqueue(new TestEvent(), onHandled: null)); // no exception, successful call
            Assert.True(queue.HandleNext());
            Assert.False(queue.HandleNext());                             // no secondary event added
        }
Beispiel #11
0
        public static void EnqueueUpdatesMetadata()
        {
            var queue = new ManualEventQueue();
            var evnt  = new NamedEvent("test");

            Assert.Null(evnt.EventEnqueuePos);
            Assert.True(queue.Enqueue(evnt));
            Assert.True(evnt.EventEnqueuePos.Contains(nameof(EnqueueUpdatesMetadata)));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DispatcherEventQueue"/> class.
        /// </summary>
        /// <param name="uiDispatcher">The <see cref="Dispatcher"/> to use for event handling.</param>
        /// <param name="priority">The <see cref="DispatcherPriority"/> to use. Background priority is the default, to keep the UI snappy.</param>
        public DispatcherEventQueue(Dispatcher uiDispatcher, DispatcherPriority priority = DispatcherPriority.Background)
        {
            if (!Enum.IsDefined(typeof(DispatcherPriority), priority))
            {
                throw new ArgumentException("Invalid priority!");
            }

            this.dispatcher              = uiDispatcher ?? throw Exc.Null(nameof(uiDispatcher));
            this.dispatcherPriority      = priority;
            this.isEventHandlerScheduled = new ThreadSafeBoolean(false);
            this.manualQueue             = new ManualEventQueue();
            this.scheduledDelegate       = new Action(this.OnScheduled);
        }
Beispiel #13
0
        public static void NoNewSubscriptionsAfterShutdown()
        {
            var queue   = new ManualEventQueue();
            var handler = new TestEventHandler();

            queue.Subscribers.AddAll(handler);

            queue.BeginShutdown();
            Assert.True(queue.HandleNext());                    // shutting down event
            Assert.True(queue.HandleNext());                    // shut down event
            Assert.True(queue.IsShutDown);
            Assert.False(queue.Subscribers.RemoveAll(handler)); // a shutdown queue has no subscribers
            Assert.False(queue.Subscribers.AddAll(new TestEventHandler(), weakRef: false));
        }
Beispiel #14
0
        private static void ShutdownEventTriggersShutdownState(ManualEventQueue manualQueue)
        {
            TestApp.MoveToState(AppState.Running);
            while (manualQueue.HandleNext())
            {
                ;
            }

            manualQueue.BeginShutdown();
            while (manualQueue.HandleNext())
            {
                ;
            }
            Assert.True(manualQueue.IsShutDown);
            Assert.AreEqual(AppState.Shutdown, TestApp.CurrentState);
        }
Beispiel #15
0
        public static void EventsCanNotBeEnqueuedTwice()
        {
            var queue = new ManualEventQueue();
            var evnt  = new TestEvent();

            // the same instance twice won't work
            queue.Enqueue(evnt);
            queue.Enqueue(evnt);
            Assert.True(queue.HandleNext());
            Assert.False(queue.HandleNext());

            // .. but two separate instances of the same event are fine
            queue.Enqueue(new TestEvent());
            queue.Enqueue(new TestEvent());
            Assert.True(queue.HandleNext());
            Assert.True(queue.HandleNext());
        }
Beispiel #16
0
        public static void EventsCanNotBeEnqueuedAfterShuttingDown()
        {
            var queue        = new ManualEventQueue();
            var testListener = new TestEventHandler();

            queue.Subscribers.AddAll(testListener);
            queue.Subscribers.Add(
                DelegateEventHandler.OnShuttingDown(
                    e => queue.Enqueue(new NamedEvent("shutting down event handler"))),
                weakRef: false);

            // enqueue shutting down event
            queue.BeginShutdown();

            // can enqueue, after the shutting down event is enqueued, but before it is handled
            Assert.True(queue.Enqueue(new TestEvent()
            {
                Value = 1
            }));

            // handle shutting down event
            Assert.True(queue.HandleNext());
            Assert.Null(testListener.LastEventHandled);

            // try to enqueue another event, after the shutting down event is handled:
            // it should have no effect
            Assert.False(queue.Enqueue(new TestEvent()
            {
                Value = 2
            }));

            // handle first test event
            Assert.True(queue.HandleNext());
            Assert.AreEqual(1, ((TestEvent)testListener.LastEventHandled).Value);

            // handle the event added in the shutting down event handler
            Assert.True(queue.HandleNext());
            Assert.IsInstanceOf <NamedEvent>(testListener.LastEventHandled); // false for null

            // handle shut down event
            Assert.True(queue.HandleNext(out var shutDownEvent));
            Assert.IsInstanceOf <ShutDownEvent>(shutDownEvent);

            // nothing more to handle
            Assert.True(queue.IsShutDown);
        }
Beispiel #17
0
        private PackageManagerResponseImpl PerformCall(InvokeMemberBinder binder, object[] args)
        {
            using (var eventQueue = new ManualEventQueue()) {
                // create return message handler
                var responseHandler = new PackageManagerResponseImpl();
                CurrentTask.Events += new GetCurrentRequestId(() => "" + Task.CurrentId);
                // unhook the old one if it's there.
                responseHandler.Clear();

                // send OG message here!
                object callResult;
                base.TryInvokeMember(binder, args, out callResult);

                // will return when the final message comes thru.
                eventQueue.StillWorking = true;

                while (eventQueue.StillWorking && eventQueue.ResetEvent.WaitOne())
                {
                    eventQueue.ResetEvent.Reset();
                    while (eventQueue.Count > 0)
                    {
                        if (!Event <GetResponseDispatcher> .RaiseFirst().DispatchSynchronous(eventQueue.Dequeue()))
                        {
                            eventQueue.StillWorking = false;
                        }
                    }
                }

                if (PackageManagerResponseImpl.EngineRestarting)
                {
                    Logger.Message("Going to try and re issue the call.");
                    // Disconnect();
                    // the service is going to restart, let's call TryInvokeMember again.
                    EngineServiceManager.WaitForStableMoment();
                    Connect().Wait();
                    return(PerformCall(binder, args));
                }

                // this returns the final response back via the Task<*>
                return(responseHandler);
            }
        }
Beispiel #18
0
        private static void ChangeToSameState(ManualEventQueue manualQueue)
        {
            AppStateChangedEvent.Critical criticalEvent = null;
            var subscriber = DelegateEventHandler.On <AppStateChangedEvent.Critical>(
                e =>
            {
                criticalEvent = e;
            });

            TestApp.MainEventQueue.Subscribers.Add(subscriber);

            var currentState = TestApp.CurrentState;

            TestApp.MoveToState(currentState);
            Assert.AreEqual(currentState, TestApp.CurrentState); // no state change
            Assert.Null(criticalEvent);                          // no critical event
            Assert.False(manualQueue.HandleNext());              // no regular event

            TestApp.MainEventQueue.Subscribers.Remove(subscriber);
        }
Beispiel #19
0
        public static void ShuttingDownHandler()
        {
            var queue = new ManualEventQueue();

            // create subscriber
            ShuttingDownEvent lastEventHandled = null;
            var subscriber = DelegateEventHandler.OnShuttingDown(evnt => lastEventHandled = evnt);

            queue.Subscribers.Add(subscriber);

            // enqueue and handle event
            queue.BeginShutdown();
            Assert.Null(lastEventHandled);
            Assert.True(queue.HandleNext()); // shutting down event

            // test subscriber
            Assert.NotNull(lastEventHandled);
            Assert.True(queue.HandleNext()); // shut down event
            Assert.True(queue.IsShutDown);
        }
Beispiel #20
0
        public static void StatefulHandler()
        {
            var queue = new ManualEventQueue();

            // create subscriber
            TestEvent lastEventHandled = null;
            var       subscriber       = DelegateEventHandler.On(
                (int currentState, TestEvent evnt) =>
            {
                lastEventHandled = evnt;
                evnt.Value      += currentState;
                return(currentState + 1);
            },
                initialState: 10);

            queue.Subscribers.Add(subscriber);

            // enqueue events
            queue.Enqueue(new TestEvent()
            {
                Value = 3
            });
            queue.Enqueue(new TestEvent()
            {
                Value = 4
            });
            Assert.Null(lastEventHandled);

            // handle first event
            Assert.True(queue.HandleNext());
            Assert.NotNull(lastEventHandled);
            Assert.AreEqual(13, lastEventHandled.Value);

            // handle second event
            Assert.True(queue.HandleNext());
            Assert.NotNull(lastEventHandled);
            Assert.AreEqual(15, lastEventHandled.Value);

            // queue is empty again (no unhandled exceptions or anything else)
            Assert.False(queue.HandleNext());
        }
Beispiel #21
0
        public static void ShutdownRequest_NotCancelled()
        {
            var queue = new ManualEventQueue();

            bool shuttingDownDetected = false;

            queue.Subscribers.Add(
                DelegateEventHandler.OnShuttingDown(
                    e => shuttingDownDetected = true),
                weakRef: false);

            // requests are granted by default (Cancel is false)
            Assert.True(queue.RequestShutdown());
            Assert.True(queue.HandleNext()); // request event
            Assert.False(shuttingDownDetected);
            Assert.True(queue.HandleNext()); // shutting down event
            Assert.True(shuttingDownDetected);
            Assert.True(queue.HandleNext()); // shut down event
            Assert.False(queue.HandleNext());
            Assert.True(queue.IsShutDown);
        }
Beispiel #22
0
        public static void HandleNextInvokesHandler()
        {
            var queue      = new ManualEventQueue();
            var evnt       = new TestEvent();
            var subscriber = new TestEventHandler();

            // queue empty
            Assert.False(queue.HandleNext());

            // enqueueing does not invoke handlers
            queue.Subscribers.AddAll(subscriber);
            Assert.True(queue.Enqueue(evnt));
            Assert.Null(subscriber.LastEventHandled);

            // invoking handlers is successful
            Assert.True(queue.HandleNext());
            Assert.AreSame(evnt, subscriber.LastEventHandled);

            // queue is empty again
            Assert.False(queue.HandleNext());
        }
Beispiel #23
0
        public static void EventAddingSuspension()
        {
            var queue = new ManualEventQueue();

            Assert.False(queue.EventHandling.IsSuspended);

            var testListener = new TestEventHandler();

            queue.Subscribers.AddAll(testListener);
            var evnt = new TestEvent();

            queue.EventAdding.Suspend();
            Assert.False(queue.Enqueue(evnt));
            Assert.False(queue.HandleNext());
            Assert.Null(testListener.LastEventHandled);

            queue.EventAdding.Resume();
            Assert.True(queue.Enqueue(evnt));
            Assert.True(queue.HandleNext());
            Assert.AreSame(evnt, testListener.LastEventHandled);
        }
Beispiel #24
0
        public static void ExceptionHandler()
        {
            var queue = new ManualEventQueue();

            // create subscriber
            UnhandledExceptionEvent lastEventHandled = null;
            var subscriber = DelegateEventHandler.OnException(evnt => lastEventHandled = evnt);

            queue.Subscribers.Add(subscriber);

            // enqueue and handle event
            queue.Enqueue(new UnhandledExceptionEvent(new UnauthorizedAccessException()));
            Assert.Null(lastEventHandled);
            Assert.True(queue.HandleNext());

            // test subscriber
            Assert.NotNull(lastEventHandled);
            Test.OrdinalEquals(lastEventHandled.Type, typeof(UnauthorizedAccessException).ToString());

            // queue is empty again (no unhandled exceptions or anything else)
            Assert.False(queue.HandleNext());
        }
Beispiel #25
0
        public void Disconnect()
        {
            _isProcessingMessages.Reset();
            lock (this) {
                _connectingTask = null;

                try {
                    if (_pipe != null)
                    {
                        // ensure all queues are stopped and cleared out.
                        ManualEventQueue.ResetAllQueues();
                        _isBufferReady.Set();
                        var pipe = _pipe;
                        _pipe = null;
                        pipe.Close();
                        pipe.Dispose();
                    }
                } catch {
                    // just close it!
                }
            }
        }
Beispiel #26
0
        public static void ShutdownRequest_Cancelled()
        {
            var queue = new ManualEventQueue();

            queue.Subscribers.Add(
                DelegateEventHandler.OnShutdownRequest(
                    e => e.Cancel = true),
                weakRef: false);

            // you can only add one request at a time
            Assert.True(queue.RequestShutdown());
            Assert.False(queue.RequestShutdown());

            // cancel the request
            Assert.True(queue.HandleNext());

            // no shutting down event
            Assert.False(queue.HandleNext());

            // you can add another request, once the previous one is out of the queue
            Assert.True(queue.RequestShutdown());
            Assert.True(queue.HandleNext());
            Assert.False(queue.HandleNext());
        }
Beispiel #27
0
 public static void ShutdownRequest_IgnoredAfterShuttingDown()
 {
     var queue = new ManualEventQueue();
 }
Beispiel #28
0
        private void ProcessMessages()
        {
            var incomingMessage = new byte[BufferSize];

            _isBufferReady.Set();

            try {
                // tell others that we are indeed processing messages.
                _isProcessingMessages.Set();

                do
                {
                    // we need to wait for the buffer to become available.
                    _isBufferReady.WaitOne();


                    // now we claim the buffer
                    _isBufferReady.Reset();
                    Task <int> readTask;
                    readTask = _pipe.ReadAsync(incomingMessage, 0, BufferSize);

                    readTask.ContinueWith(
                        antecedent => {
                        if (antecedent.IsCanceled || antecedent.IsFaulted || !IsConnected)
                        {
                            if (antecedent.IsCanceled)
                            {
                                Logger.Message("Client/Session ReadTask is Cancelled");
                            }
                            if (antecedent.IsFaulted)
                            {
                                Logger.Message("Client/Session ReadTask is Faulted : {0}", antecedent.Exception.GetType());
                            }
                            Disconnect();
                            return;
                        }
                        if (antecedent.Result > 0)
                        {
                            var rawMessage      = Encoding.UTF8.GetString(incomingMessage, 0, antecedent.Result);
                            var responseMessage = new UrlEncodedMessage(rawMessage);
                            var rqid            = responseMessage["rqid"].ToInt32();

                            // lazy log the response (since we're at the end of this task)
                            Logger.Message("Response:[{0}]{1}".format(rqid, responseMessage.ToSmallerString()));

                            try {
                                var queue = ManualEventQueue.GetQueue(rqid);
                                if (queue != null)
                                {
                                    queue.Enqueue(responseMessage);
                                }
                                //else {
                                // GS01 : Need to put in protocol version detection.
                                //}
                            } catch {
                            }
                        }
                        // it's ok to let the next readTask use the buffer, we've got the data out & queued.
                        _isBufferReady.Set();
                    }).AutoManage();

                    // this wait just makes sure that we're only asking for one message at a time
                    // but does not throttle the messages themselves.
                    // readTask.Wait();
                } while (IsConnected);
            } catch (Exception e) {
                Logger.Message("Connection Terminating with Exception {0}/{1}", e.GetType(), e.Message);
            } finally {
                Logger.Message("In ProcessMessages/Finally");
                Disconnect();
            }
        }
Beispiel #29
0
        public static void EventHandlerExceptions()
        {
            var queue = new ManualEventQueue();

            queue.Subscribers.Add(
                DelegateEventHandler.On <TestEvent>(
                    e => throw new ArgumentOutOfRangeException()),
                weakRef: false);

            queue.Subscribers.Add(
                DelegateEventHandler.On <TestEvent>(
                    e => throw new MissingMemberException()),
                weakRef: false);

            bool argumentExceptionFound         = false;
            bool memberExceptionFound           = false;
            bool unhandledExceptionEventHandled = false;

            queue.Subscribers.Add(
                DelegateEventHandler.On <UnhandledExceptionEvent>(
                    e =>
            {
                unhandledExceptionEventHandled = true;

                if (e.Type.IndexOf(nameof(ArgumentOutOfRangeException), StringComparison.Ordinal) != -1)
                {
                    argumentExceptionFound = true;
                }
                else if (e.Type.IndexOf(nameof(MissingMemberException), StringComparison.Ordinal) != -1)
                {
                    memberExceptionFound = true;
                }
            }),
                weakRef: false);

            // unhandled exception events are generated by default
            queue.Enqueue(new TestEvent());
            Assert.False(argumentExceptionFound);
            Assert.False(memberExceptionFound);
            Assert.False(unhandledExceptionEventHandled);
            Assert.True(queue.HandleNext()); // test event
            Assert.True(queue.HandleNext()); // argument exception
            Assert.True(queue.HandleNext()); // missing member exception
            Assert.True(argumentExceptionFound);
            Assert.True(memberExceptionFound);
            Assert.True(unhandledExceptionEventHandled);

            // unhandled exception event suppression
            queue.Enqueue(new TestEvent());
            argumentExceptionFound         = false;
            memberExceptionFound           = false;
            unhandledExceptionEventHandled = false;
            queue.RaiseUnhandledEvents.Suspend();
            Assert.True(queue.HandleNext());
            Assert.False(queue.HandleNext());
            queue.RaiseUnhandledEvents.Resume();
            Assert.False(argumentExceptionFound);
            Assert.False(memberExceptionFound);
            Assert.False(unhandledExceptionEventHandled);

            // event addition suppression
            queue.Enqueue(new TestEvent());
            queue.EventAdding.Suspend();
            Assert.True(queue.HandleNext());
            Assert.False(queue.HandleNext());
            queue.EventAdding.Resume();
            Assert.False(argumentExceptionFound);
            Assert.False(memberExceptionFound);
            Assert.False(unhandledExceptionEventHandled);
        }