public void RegisterTask_AsynchronousCompletion_SwallowsExceptionsThrownByEndDelegate() {
            // Arrange
            SimpleSynchronizationContext syncContext = new SimpleSynchronizationContext();
            AsyncManager asyncManager = new AsyncManager(syncContext);
            bool endDelegateWasCalled = false;

            ManualResetEvent waitHandle = new ManualResetEvent(false /* initialState */);

            Func<AsyncCallback, IAsyncResult> beginDelegate = callback => {
                MockAsyncResult asyncResult = new MockAsyncResult(false /* completedSynchronously */);
                ThreadPool.QueueUserWorkItem(_ => {
                    callback(asyncResult);
                    waitHandle.Set();
                });
                return asyncResult;
            };
            Action<IAsyncResult> endDelegate = delegate {
                endDelegateWasCalled = true;
                throw new Exception("This is a sample exception.");
            };

            // Act
            asyncManager.RegisterTask(beginDelegate, endDelegate);
            waitHandle.WaitOne();

            // Assert
            Assert.IsTrue(endDelegateWasCalled);
            Assert.AreEqual(0, asyncManager.OutstandingOperations.Count, "Counter was not decremented properly.");
        }
        public void RegisterTask_AsynchronousCompletion() {
            // Arrange
            SimpleSynchronizationContext syncContext = new SimpleSynchronizationContext();
            AsyncManager asyncManager = new AsyncManager(syncContext);
            bool endDelegateWasCalled = false;

            ManualResetEvent waitHandle = new ManualResetEvent(false /* initialState */);

            Func<AsyncCallback, IAsyncResult> beginDelegate = callback => {
                Assert.AreEqual(1, asyncManager.OutstandingOperations.Count, "Counter was not incremented properly.");
                MockAsyncResult asyncResult = new MockAsyncResult(false /* completedSynchronously */);
                ThreadPool.QueueUserWorkItem(_ => {
                    Assert.AreEqual(1, asyncManager.OutstandingOperations.Count, "Counter shouldn't have been decremented yet.");
                    callback(asyncResult);
                    waitHandle.Set();
                });
                return asyncResult;
            };
            Action<IAsyncResult> endDelegate = delegate { endDelegateWasCalled = true; };

            // Act
            asyncManager.RegisterTask(beginDelegate, endDelegate);
            waitHandle.WaitOne();

            // Assert
            Assert.IsTrue(endDelegateWasCalled);
            Assert.IsTrue(syncContext.SendWasCalled, "Asynchronous call to End() should have been routed through SynchronizationContext.Send()");
            Assert.AreEqual(0, asyncManager.OutstandingOperations.Count, "Counter was not decremented properly.");
        }
        public void RegisterTask_SynchronousCompletion() {
            // Arrange
            SimpleSynchronizationContext syncContext = new SimpleSynchronizationContext();
            AsyncManager asyncManager = new AsyncManager(syncContext);
            bool endDelegateWasCalled = false;

            Func<AsyncCallback, IAsyncResult> beginDelegate = callback => {
                Assert.AreEqual(1, asyncManager.OutstandingOperations.Count, "Counter was not incremented properly.");
                MockAsyncResult asyncResult = new MockAsyncResult(true /* completedSynchronously */);
                callback(asyncResult);
                return asyncResult;
            };
            Action<IAsyncResult> endDelegate = delegate { endDelegateWasCalled = true; };

            // Act
            asyncManager.RegisterTask(beginDelegate, endDelegate);

            // Assert
            Assert.IsTrue(endDelegateWasCalled);
            Assert.IsFalse(syncContext.SendWasCalled, "Synchronous call to End() should not have been routed through SynchronizationContext.Send()");
            Assert.AreEqual(0, asyncManager.OutstandingOperations.Count, "Counter was not decremented properly.");
        }
        public void RegisterTask_ResetsOutstandingOperationCountIfBeginMethodThrows() {
            // Arrange
            SimpleSynchronizationContext syncContext = new SimpleSynchronizationContext();
            AsyncManager asyncManager = new AsyncManager(syncContext);

            Func<AsyncCallback, IAsyncResult> beginDelegate = cb => {
                throw new InvalidOperationException("BeginDelegate throws.");
            };
            Action<IAsyncResult> endDelegate = ar => {
                Assert.Fail("This should never be called.");
            };

            // Act & assert
            ExceptionHelper.ExpectInvalidOperationException(
                delegate {
                    asyncManager.RegisterTask(beginDelegate, endDelegate);
                }, "BeginDelegate throws.");

            Assert.AreEqual(0, asyncManager.OutstandingOperations.Count);
        }