using System; using System.Collections.Generic; using System.Reflection; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace UnitTests.Common.Utilities { [TestClass] [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public class AsyncQueueTests { private Queue internalQueue; private TestElement queueElement1; private TestElement queueElement2; private TestElement queueElement3; [TestInitialize] public void InitializeTest() { queueElement1 = new TestElement { Number = 111, Text = "one" }; queueElement2 = new TestElement { Number = 222, Text = "two" }; queueElement3 = new TestElement { Number = 333, Text = "three" }; internalQueue = new Queue(); internalQueue.Enqueue(queueElement1); internalQueue.Enqueue(queueElement2); internalQueue.Enqueue(queueElement3); } [TestMethod] public void ShouldEnqueueItem() { // arrange var element = new TestElement { Number = 1, Text = "Hello" }; internalQueue.Clear(); var queue = GetQueue(); // act queue.Enqueue(element); // assert Assert.AreEqual(1, internalQueue.Count); Assert.AreEqual(internalQueue.Count, queue.Count); } [TestMethod] public void ShouldEnqueueItemAndResetAvailableToken() { // arrange var element = new TestElement { Number = 1, Text = "Hello" }; bool available = false; internalQueue.Clear(); var queue = GetQueue(); // act var task = Task.Run(async () => { await queue.WaitAsync(); available = true; }); queue.Enqueue(element); task.Wait(); // assert Assert.IsTrue(available); } [TestMethod] public void ShouldEnqueueItemAndResetDequeueToken() { // arrange var element = new TestElement { Number = 1, Text = "Hello" }; TestElement callback = null; internalQueue.Clear(); var queue = GetQueue(); // act var task = Task.Run(async () => { callback = await queue.DequeueAsync(); }); queue.Enqueue(element); task.Wait(); // assert Assert.IsNotNull(callback); Assert.AreEqual(element, callback); } [TestMethod] public void ShouldEnqueueMultipleItems() { // arrange var elements = new TestElement[] { new TestElement { Number = 1, Text = "Hello" }, new TestElement { Number = 2, Text = "World" }, }; internalQueue.Clear(); var queue = GetQueue(); // act queue.Enqueue(elements); // assert Assert.AreEqual(2, internalQueue.Count); Assert.AreEqual(queue.Count, internalQueue.Count); } [TestMethod] public void ShouldPeekAValue() { // arrange var queue = GetQueue(); // act bool isSuccess = queue.TryPeek(out var item); // assert Assert.IsTrue(isSuccess); Assert.IsNotNull(item); Assert.AreEqual(queueElement1, item); Assert.AreEqual(3, queue.Count); } [TestMethod] public void ShouldNotPeekAValue() { // arrange internalQueue.Clear(); var queue = GetQueue(); // act bool isSuccess = queue.TryPeek(out var item); // assert Assert.IsFalse(isSuccess); Assert.IsNull(item); } [TestMethod] public void ShouldDequeueAValue() { // arrange var queue = GetQueue(); // act bool isSuccess = queue.TryDequeue(out var item); // assert Assert.IsTrue(isSuccess); Assert.IsNotNull(item); Assert.AreEqual(queueElement1, item); Assert.AreEqual(2, queue.Count); } [TestMethod] public void ShouldNotDequeueAValue() { // arrange internalQueue.Clear(); var queue = GetQueue(); // act bool isSuccess = queue.TryDequeue(out var item); // assert Assert.IsFalse(isSuccess); Assert.IsNull(item); } [TestMethod] public void ShouldRemoveAValue() { // arrange var queue = GetQueue(); // act queue.Remove(queueElement2); var item1 = queue.Dequeue(); var item2 = queue.Dequeue(); // assert Assert.AreEqual(0, queue.Count); Assert.AreEqual(queueElement1, item1); Assert.AreEqual(queueElement3, item2); } [TestMethod] public void ShouldNotRemoveAValue() { // arrange var queue = GetQueue(); // act queue.Remove(null); var item1 = queue.Dequeue(); var item2 = queue.Dequeue(); var item3 = queue.Dequeue(); // assert Assert.AreEqual(0, queue.Count); Assert.AreEqual(queueElement1, item1); Assert.AreEqual(queueElement2, item2); Assert.AreEqual(queueElement3, item3); } [TestMethod] public async Task ShouldAwaitOneDequeue() { // arrange internalQueue.Clear(); var queue = GetQueue(); var task = Task.Run(async () => { await Task.Delay(1000); queue.Enqueue(new[] { queueElement1, queueElement2, queueElement3 }); }); // act var item = await queue.DequeueAsync(); // assert Assert.AreEqual(2, queue.Count); Assert.IsNotNull(item); Assert.AreEqual(queueElement1, item); } [TestMethod] public async Task ShouldAwaitManyDequeue() { // arrange internalQueue.Clear(); var queue = GetQueue(); var task = Task.Run(async () => { await Task.Delay(1000); queue.Enqueue(new[] { queueElement1, queueElement2, queueElement3 }); }); // act var items = await queue.DequeueManyAsync(2); // assert Assert.AreEqual(1, queue.Count); Assert.IsNotNull(items); Assert.AreEqual(2, items.Length); Assert.AreEqual(queueElement1, items[0]); Assert.AreEqual(queueElement2, items[1]); } [TestMethod] public async Task ShouldAwaitAllDequeue() { // arrange internalQueue.Clear(); var queue = GetQueue(); var task = Task.Run(async () => { await Task.Delay(1000); queue.Enqueue(new[] { queueElement1, queueElement2, queueElement3 }); }); // act var items = await queue.DequeueAvailableAsync(); // assert Assert.AreEqual(0, queue.Count); Assert.IsNotNull(items); Assert.AreEqual(3, items.Length); Assert.AreEqual(queueElement1, items[0]); Assert.AreEqual(queueElement2, items[1]); Assert.AreEqual(queueElement3, items[2]); } [TestMethod] public async Task ShouldAwaitAvailableDequeue() { // arrange internalQueue.Clear(); var queue = GetQueue(); var task = Task.Run(async () => { await Task.Delay(1000); queue.Enqueue(new[] { queueElement1, queueElement2, queueElement3 }); }); // act var items = await queue.DequeueAvailableAsync(2); // assert Assert.AreEqual(1, queue.Count); Assert.IsNotNull(items); Assert.AreEqual(2, items.Length); Assert.AreEqual(queueElement1, items[0]); Assert.AreEqual(queueElement2, items[1]); } [TestMethod] [ExpectedException(typeof(ArgumentOutOfRangeException))] public async Task ShouldThrowArumentOutOfRangeException() { // arrange internalQueue.Clear(); var queue = GetQueue(); // act await queue.DequeueManyAsync(-2); // assert - ArgumentOutOfRangeException expected Assert.Fail(); } private AsyncQueue GetQueue() { var asyncQueue = new AsyncQueue(); var field = asyncQueue.GetType().GetField("queue", BindingFlags.Instance | BindingFlags.NonPublic); field.SetValue(asyncQueue, internalQueue); return asyncQueue; } private class TestElement { public int Number { get; set; } public string Text { get; set; } } } }