public async Task NoRaceBetweenFlushOnAddAndOnDemand()
        {
            const int attempts  = 100 * 1000;
            const int batchSize = 5;

            _queue = new AsyncBatchQueue <int>(batchSize);

            for (int attemptNumber = 0; attemptNumber < attempts; attemptNumber++)
            {
                AddAllItemsButOne(batchSize);

                using (ManualResetEvent trigger = new ManualResetEvent(initialState: false))
                {
                    Task addTask = Task.Run
                                   (
                        () =>
                    {
                        trigger.WaitOne();
                        _queue.Add(666);
                    }
                                   );

                    Task flushTask = Task.Run
                                     (
                        () =>
                    {
                        trigger.WaitOne();
                        _queue.Flush();
                    }
                                     );

                    trigger.Set();
                    await addTask.ConfigureAwait(true);

                    await flushTask.ConfigureAwait(true);

                    IReadOnlyList <int> batch = await _queue.TakeAsync().ConfigureAwait(true);

                    List <int> allItems = batch.ToList();

                    // This happens if Flush occurred before Add, which means there's another item from Add left unflushed.
                    // Gotta flush once more to extract it.
                    if (batch.Count < batchSize)
                    {
                        _queue.Flush();
                        IReadOnlyList <int> secondBatch = await _queue.TakeAsync().ConfigureAwait(true);

                        allItems.AddRange(secondBatch);
                    }

                    allItems.Count.Should().BeLessOrEqualTo(batchSize, $"Double flush detected at attempt #{attemptNumber}. Items: {String.Join( ", ", allItems )}");
                }
            }
        }
        public async Task MultithreadingInsertsDontCrash()
        {
            int insertThreads  = 4;
            int itemsPerThread = 100;

            _queue = new AsyncBatchQueue <int>(11);

            List <Task> insertTasks = Enumerable.Range(1, insertThreads)
                                      .Select(
                _ => Task.Run(
                    () =>
            {
                for (int i = 0; i < itemsPerThread; i++)
                {
                    _queue.Add(42);
                }
            }))
                                      .ToList();

            await Task.WhenAll(insertTasks).ConfigureAwait(true);

            _queue.Flush();

            int itemsTaken = 0;

            while (_queue.Count > 0)
            {
                itemsTaken += (await _queue.TakeAsync().ConfigureAwait(true)).Count;
            }

            itemsTaken.Should().Be(insertThreads * itemsPerThread);
        }
		public async Task ManualFlushWorks()
		{
			int[] array = { 0, 1, 42 };

			_queue = new AsyncBatchQueue<int>( 50 );
			foreach ( var item in array )
				_queue.Add( item );

			_queue.Flush();
			var batch = await _queue.TakeAsync();

			CollectionAssert.AreEqual( array, batch.ToList() );
		}
        public async Task ManualFlushWorks()
        {
            int[] array = { 0, 1, 42 };

            _queue = new AsyncBatchQueue <int>(50);
            foreach (var item in array)
            {
                _queue.Add(item);
            }

            _queue.Flush();
            var batch = await _queue.TakeAsync().ConfigureAwait(true);

            batch.Should().BeEqualTo(array);
        }
		public async Task MultithreadingInsertsDontCrash()
		{
			int insertThreads = 4;
			int itemsPerThread = 100;

			_queue = new AsyncBatchQueue<int>( 11 );

			List<Task> insertTasks = Enumerable.Range( 1, insertThreads )
				.Select(
					_ => Task.Run(
						() =>
						{
							for ( int i = 0; i < itemsPerThread; i++ )
								_queue.Add( 42 );
						} ) )
				.ToList();

			await Task.WhenAll( insertTasks );
			_queue.Flush();

			int itemsTaken = 0;
			while ( _queue.Count > 0 )
				itemsTaken += ( await _queue.TakeAsync() ).Count;

			Assert.AreEqual( insertThreads * itemsPerThread, itemsTaken );
		}