void TestPrimitiveObjectPoolsDispose()
        {
            PrimitiveObjectPool <TestObjectPoolItem>          primPool   = new PrimitiveObjectPool <TestObjectPoolItem>(1);
            ResizablePrimitiveObjectPool <TestObjectPoolItem> resizePool = new ResizablePrimitiveObjectPool <TestObjectPoolItem>(1);
            BlockingPrimitiveObjectPool <TestObjectPoolItem>  blockPool  = new BlockingPrimitiveObjectPool <TestObjectPoolItem>(1);

            primPool.Dispose();
            resizePool.Dispose();
            blockPool.Dispose();

            Assert.Throws <ObjectDisposedException>(() => primPool.InUse);
            Assert.Throws <ObjectDisposedException>(() => primPool.PoolCount);
            Assert.Throws <ObjectDisposedException>(() => primPool.Size);
            Assert.Throws <ObjectDisposedException>(() => primPool.TryObtain(out var item));
            Assert.Throws <ObjectDisposedException>(() => primPool.TryRelease(new TestObjectPoolItem()));
            Assert.Throws <ObjectDisposedException>(() => primPool.Obtain());
            Assert.Throws <ObjectDisposedException>(() => primPool.Release(new TestObjectPoolItem()));

            Assert.Throws <ObjectDisposedException>(() => resizePool.InUse);
            Assert.Throws <ObjectDisposedException>(() => resizePool.PoolCount);
            Assert.Throws <ObjectDisposedException>(() => resizePool.Size);
            Assert.Throws <ObjectDisposedException>(() => resizePool.TryObtain(out var item));
            Assert.Throws <ObjectDisposedException>(() => resizePool.TryRelease(new TestObjectPoolItem()));
            Assert.Throws <ObjectDisposedException>(() => resizePool.Obtain());
            Assert.Throws <ObjectDisposedException>(() => resizePool.Release(new TestObjectPoolItem()));

            Assert.Throws <ObjectDisposedException>(() => blockPool.InUse);
            Assert.Throws <ObjectDisposedException>(() => blockPool.PoolCount);
            Assert.Throws <ObjectDisposedException>(() => blockPool.Size);
            Assert.Throws <ObjectDisposedException>(() => blockPool.TryObtain(out var item));
            Assert.Throws <ObjectDisposedException>(() => blockPool.TryRelease(new TestObjectPoolItem()));
            Assert.Throws <ObjectDisposedException>(() => blockPool.Obtain());
            Assert.Throws <ObjectDisposedException>(() => blockPool.Release(new TestObjectPoolItem()));
        }
        void TestPrimitiveObjectPoolsCreation()
        {
            PrimitiveObjectPool <TestObjectPoolItem>          primPool   = null;
            ResizablePrimitiveObjectPool <TestObjectPoolItem> resizePool = null;
            BlockingPrimitiveObjectPool <TestObjectPoolItem>  blockPool  = null;

            Assert.Throws <ArgumentOutOfRangeException>(() =>
            {
                primPool = new PrimitiveObjectPool <TestObjectPoolItem>(0);
            });

            Assert.Throws <ArgumentOutOfRangeException>(() =>
            {
                resizePool = new ResizablePrimitiveObjectPool <TestObjectPoolItem>(0);
            });

            Assert.Throws <ArgumentOutOfRangeException>(() =>
            {
                blockPool = new BlockingPrimitiveObjectPool <TestObjectPoolItem>(0);
            });

            Assert.Null(primPool);
            Assert.Null(resizePool);
            Assert.Null(blockPool);

            primPool   = new PrimitiveObjectPool <TestObjectPoolItem>(1);
            resizePool = new ResizablePrimitiveObjectPool <TestObjectPoolItem>(1);
            blockPool  = new BlockingPrimitiveObjectPool <TestObjectPoolItem>(1);

            Assert.NotNull(primPool);
            Assert.NotNull(resizePool);
            Assert.NotNull(blockPool);
        }
        void TestBlockingPrimitiveObjectPoolObtainRelease()
        {
            BlockingPrimitiveObjectPool <TestObjectPoolItem> blockPool = new BlockingPrimitiveObjectPool <TestObjectPoolItem>(3);

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(0, blockPool.InUse);
            Assert.Equal(3, blockPool.PoolCount);

            TestObjectPoolItem test = new TestObjectPoolItem();

            Assert.False(blockPool.TryRelease(test));

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(0, blockPool.InUse);
            Assert.Equal(3, blockPool.PoolCount);

            AutoResetEvent autoResetEvent = new AutoResetEvent(false);

            Task.Run(() =>
            {
                autoResetEvent.Set();
                blockPool.Release(test);
                autoResetEvent.Set();
            });

            autoResetEvent.WaitOne();

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(0, blockPool.InUse);
            Assert.Equal(3, blockPool.PoolCount);

            var newTest = blockPool.Obtain();

            autoResetEvent.WaitOne();

            Assert.NotNull(newTest);
            Assert.Equal(3, blockPool.Size);
            Assert.Equal(0, blockPool.InUse);
            Assert.Equal(3, blockPool.PoolCount);

            TestObjectPoolItem test1;
            TestObjectPoolItem test2;
            TestObjectPoolItem test3;
            TestObjectPoolItem test4;
            TestObjectPoolItem test5 = null;

            Assert.True(blockPool.TryObtain(out test1));

            Assert.NotNull(test1);
            Assert.Equal(3, blockPool.Size);
            Assert.Equal(1, blockPool.InUse);
            Assert.Equal(2, blockPool.PoolCount);

            test2 = blockPool.Obtain();

            Assert.NotNull(test2);
            Assert.Equal(3, blockPool.Size);
            Assert.Equal(2, blockPool.InUse);
            Assert.Equal(1, blockPool.PoolCount);

            test3 = blockPool.Obtain();

            Assert.NotNull(test3);
            Assert.Equal(3, blockPool.Size);
            Assert.Equal(3, blockPool.InUse);
            Assert.Equal(0, blockPool.PoolCount);

            Assert.False(blockPool.TryObtain(out test4));

            Assert.Null(test4);
            Assert.Equal(3, blockPool.Size);
            Assert.Equal(3, blockPool.InUse);
            Assert.Equal(0, blockPool.PoolCount);

            Task.Run(() =>
            {
                autoResetEvent.Set();
                test4 = blockPool.Obtain();
                autoResetEvent.Set();
            });

            Task.Run(() =>
            {
                autoResetEvent.Set();
                test5 = blockPool.Obtain();
                autoResetEvent.Set();
            });

            autoResetEvent.WaitOne();
            autoResetEvent.WaitOne();

            Assert.Null(test4);
            Assert.Null(test5);

            blockPool.Release(test1);

            autoResetEvent.WaitOne();

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(3, blockPool.InUse);
            Assert.Equal(0, blockPool.PoolCount);

            Assert.True((test4 != null) ^ (test5 != null));

            blockPool.Release(test1);

            autoResetEvent.WaitOne();

            Assert.NotNull(test4);
            Assert.NotNull(test5);

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(3, blockPool.InUse);
            Assert.Equal(0, blockPool.PoolCount);

            Assert.True(blockPool.TryRelease(test1));

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(2, blockPool.InUse);
            Assert.Equal(1, blockPool.PoolCount);

            blockPool.Release(test1);

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(1, blockPool.InUse);
            Assert.Equal(2, blockPool.PoolCount);

            blockPool.Release(test1);

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(0, blockPool.InUse);
            Assert.Equal(3, blockPool.PoolCount);

            bool dispose1 = false;
            bool dispose2 = false;

            Task.Run(() =>
            {
                try
                {
                    autoResetEvent.Set();
                    blockPool.Release(test1);
                }
                catch (ObjectDisposedException ex)
                {
                    dispose1 = true;
                    autoResetEvent.Set();
                }
            });

            Task.Run(() =>
            {
                try
                {
                    autoResetEvent.Set();
                    blockPool.Release(test2);
                }
                catch (ObjectDisposedException ex)
                {
                    dispose2 = true;
                    autoResetEvent.Set();
                }
            });

            autoResetEvent.WaitOne();
            autoResetEvent.WaitOne();

            Assert.Equal(3, blockPool.Size);
            Assert.Equal(0, blockPool.InUse);
            Assert.Equal(3, blockPool.PoolCount);

            blockPool.Dispose();

            autoResetEvent.WaitOne();
            autoResetEvent.WaitOne();

            Assert.True(dispose1);
            Assert.True(dispose2);
        }