using System; using System.Collections.Generic; using System.Reflection; using System.Threading.Tasks; namespace AMWD.Common.Tests.Utilities { [TestClass] public class AsyncQueueTest { 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() { Number = 1, Text = "Hello" }, new() { 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; } } } }