public void TestDisposeInterruptWaitersOnAdd()
        {
            BlockingBatchingQueue <int> queue = new BlockingBatchingQueue <int>(batchSize: 2, boundedCapacityInBatches: 1);

            queue.Add(1);
            queue.Add(2);
            Barrier bar = new Barrier(2);

            Task disposeTask = Task.Run(() =>
            {
                bar.SignalAndWait();
                Thread.Sleep(10);
                queue.Dispose();
            });

            try
            {
                bar.SignalAndWait();
                bool added = queue.TryAdd(3, 10000);
                Assert.Fail();
            }
            catch (OperationInterruptedException)
            {
            }
            catch (ObjectDisposedException)
            {
            }
            catch (Exception)
            {
                Assert.Fail("Unexpected exception");
            }


            disposeTask.Wait();
        }
        public void TestQueueEnumeration()
        {
            const int batchSize             = 17;
            BlockingBatchingQueue <int> col = new BlockingBatchingQueue <int>(batchSize: batchSize);

            for (int i = 0; i < 113; i++)
            {
                col.Add(i);

                int j = 0;
                foreach (var item in col)
                {
                    Assert.AreEqual(j, item);
                    j++;
                }
                Assert.AreEqual(j - 1, i);
            }

            int offset       = 0;
            int initialCount = col.Count;

            while (col.TryTake(out int[] items))
            {
                offset += items.Length;

                int j = offset;
                foreach (var item in col)
                {
                    Assert.AreEqual(j, item);
                    j++;
                }
                Assert.AreEqual(j - 1, initialCount - 1);
            }
        }
        public void TestTimeoutWorks()
        {
            const int batchSize = 17;
            BlockingBatchingQueue <int> queue = new BlockingBatchingQueue <int>(batchSize: batchSize, boundedCapacityInBatches: 8);
            Barrier bar        = new Barrier(2);
            int     takeResult = 0;
            int     addResult  = 0;
            Task    task       = Task.Run(() =>
            {
                bar.SignalAndWait();
                int[] item = null;
                if (queue.TryTake(out item, 100))
                {
                    Interlocked.Exchange(ref takeResult, 1);
                }
                else
                {
                    Interlocked.Exchange(ref takeResult, 2);
                }

                while (queue.TryAdd(-1))
                {
                    ;
                }

                if (queue.TryAdd(100, 100))
                {
                    Interlocked.Exchange(ref addResult, 1);
                }
                else
                {
                    Interlocked.Exchange(ref addResult, 2);
                }
            });

            bar.SignalAndWait();

            TimingAssert.AreEqual(10000, 2, () => Volatile.Read(ref takeResult), "take");
            TimingAssert.AreEqual(10000, 2, () => Volatile.Read(ref addResult), "Add");

            task.Wait();
        }
        public void TestSimpleEnqueueDequeue()
        {
            const int batchSize             = 20;
            BlockingBatchingQueue <int> col = new BlockingBatchingQueue <int>(batchSize: batchSize);

            for (int i = 0; i < 100; i++)
            {
                Assert.AreEqual(i, col.Count);
                Assert.AreEqual(i / batchSize, col.CompletedBatchCount);
                col.Add(i);
            }

            Assert.AreEqual(100, col.Count);
            int expectedCount = 100;

            while (true)
            {
                bool dequeueRes = col.TryTake(out int[] batch);
                if (!dequeueRes)
                {
                    break;
                }

                Assert.IsNotNull(batch);
                Assert.AreEqual(batchSize, batch.Length);
                for (int i = 0; i < batch.Length; i++)
                {
                    Assert.AreEqual(i + (100 - expectedCount), batch[i]);
                }

                expectedCount -= batch.Length;
                Assert.AreEqual(expectedCount, col.Count);
                Assert.AreEqual(expectedCount / batchSize, col.CompletedBatchCount);
            }

            Assert.AreEqual(0, col.Count);
        }
        private void TestCancellationNotCorruptDataCore(int batchSize, int boundedCapacityInBatches)
        {
            BlockingBatchingQueue <long> col = new BlockingBatchingQueue <long>(batchSize: batchSize, boundedCapacityInBatches: boundedCapacityInBatches);
            Barrier bar = new Barrier(4);
            CancellationTokenSource cancelToken              = new CancellationTokenSource();
            CancellationTokenSource temporaryCancelTokenAdd  = new CancellationTokenSource();
            CancellationTokenSource temporaryCancelTokenTake = new CancellationTokenSource();

            List <long> takenItems = new List <long>();

            Task addTask = Task.Run(() =>
            {
                Random rnd = new Random();
                bar.SignalAndWait();
                long data = 0;
                CancellationToken token = temporaryCancelTokenAdd.Token;
                while (!cancelToken.IsCancellationRequested)
                {
                    try
                    {
                        col.Add(data, token);
                        data++;
                    }
                    catch (OperationCanceledException)
                    {
                        token = temporaryCancelTokenAdd.Token;
                    }
                }
            });

            Task takeTask = Task.Run(() =>
            {
                bar.SignalAndWait();

                CancellationToken token = temporaryCancelTokenTake.Token;
                while (!cancelToken.IsCancellationRequested)
                {
                    try
                    {
                        long[] itemsT = col.Take(token);
                        takenItems.AddRange(itemsT);
                    }
                    catch (OperationCanceledException)
                    {
                        token = temporaryCancelTokenTake.Token;
                    }

                    if (takenItems.Count > int.MaxValue / 2)
                    {
                        cancelToken.Cancel();
                    }
                }
            });


            Task cancelTask = Task.Run(() =>
            {
                Random rnd = new Random();
                bar.SignalAndWait();

                while (!cancelToken.IsCancellationRequested)
                {
                    if (rnd.Next(100) == 1)
                    {
                        temporaryCancelTokenAdd.Cancel();
                        temporaryCancelTokenAdd = new CancellationTokenSource();
                    }
                    if (rnd.Next(100) == 1)
                    {
                        temporaryCancelTokenTake.Cancel();
                        temporaryCancelTokenTake = new CancellationTokenSource();
                    }

                    SpinWaitHelper.SpinWait(rnd.Next(12));
                }
            });

            bar.SignalAndWait();
            Thread.Sleep(500);
            cancelToken.Cancel();
            temporaryCancelTokenAdd.Cancel();
            temporaryCancelTokenTake.Cancel();

            Task.WaitAll(addTask, takeTask, cancelTask);

            while (col.TryTake(out long[] itemsF))
            {
                takenItems.AddRange(itemsF);
            }

            col.CompleteCurrentBatch();

            if (col.TryTake(out long[] itemsFF))
            {
                takenItems.AddRange(itemsFF);
            }

            for (int i = 0; i < takenItems.Count; i++)
            {
                Assert.AreEqual(i, takenItems[i]);
            }
        }