using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Masuit.Tools.Systems; using Xunit; namespace Masuit.Tools.Abstractions.Test.Systems; /// /// ConcurrentHashQueue<T> 的单元测试类 /// public class ConcurrentHashQueueTests { #region 构造函数测试 [Fact] public void Constructor_Default_CreatesEmptyQueue() { // Arrange & Act var queue = new ConcurrentHashQueue(); // Assert Assert.Empty(queue); Assert.Equal(0, queue.Count); Assert.True(queue.IsEmpty); } [Fact] public void Constructor_WithComparer_UsesProvidedComparer() { // Arrange var comparer = EqualityComparer.Default; // Act var queue = new ConcurrentHashQueue(comparer); // Assert Assert.NotNull(queue); Assert.True(queue.IsEmpty); } [Fact] public void Constructor_WithCollection_InitializesWithItems() { // Arrange var items = new[] { 1, 2, 3 }; // Act var queue = new ConcurrentHashQueue(items); // Assert Assert.Equal(3, queue.Count); Assert.Contains(1, queue); Assert.Contains(2, queue); Assert.Contains(3, queue); } [Fact] public void Constructor_WithCollectionAndComparer_InitializesWithItemsAndComparer() { // Arrange var items = new[] { 1, 2, 3 }; var comparer = EqualityComparer.Default; // Act var queue = new ConcurrentHashQueue(items, comparer); // Assert Assert.Equal(3, queue.Count); } [Fact] public void Constructor_WithCollection_IgnoresDuplicates() { // Arrange var items = new[] { 1, 2, 2, 3, 1 }; // Act var queue = new ConcurrentHashQueue(items); // Assert Assert.Equal(3, queue.Count); } #endregion 构造函数测试 #region Enqueue 方法测试 [Fact] public void Enqueue_AddsSingleItem() { // Arrange var queue = new ConcurrentHashQueue(); // Act var result = queue.Enqueue(1); // Assert Assert.True(result); Assert.Single(queue); Assert.Contains(1, queue); } [Fact] public void Enqueue_ReturnsFalseForDuplicateItem() { // Arrange var queue = new ConcurrentHashQueue(); queue.Enqueue(1); // Act var result = queue.Enqueue(1); // Assert Assert.False(result); Assert.Single(queue); } [Fact] public void Enqueue_AddsMultipleUniqueItems() { // Arrange var queue = new ConcurrentHashQueue(); // Act queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); // Assert Assert.Equal(3, queue.Count); Assert.Contains(1, queue); Assert.Contains(2, queue); Assert.Contains(3, queue); } [Fact] public void Enqueue_MaintainsQueueOrder() { // Arrange var queue = new ConcurrentHashQueue(); // Act queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); // Assert var array = queue.ToArray(); Assert.Equal(1, array[0]); Assert.Equal(2, array[1]); Assert.Equal(3, array[2]); } #endregion Enqueue 方法测试 #region TryDequeue 方法测试 [Fact] public void TryDequeue_ReturnsTrueAndRemovesItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.TryDequeue(out var item); // Assert Assert.True(result); Assert.Equal(1, item); Assert.Equal(2, queue.Count); } [Fact] public void TryDequeue_ReturnsFalseWhenEmpty() { // Arrange var queue = new ConcurrentHashQueue(); // Act var result = queue.TryDequeue(out var item); // Assert Assert.False(result); Assert.Equal(default(int), item); } [Fact] public void TryDequeue_RemovesItemsInFifoOrder() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act queue.TryDequeue(out var first); queue.TryDequeue(out var second); queue.TryDequeue(out var third); // Assert Assert.Equal(1, first); Assert.Equal(2, second); Assert.Equal(3, third); } [Fact] public void TryDequeue_RemovesItemFromHashSet() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act queue.TryDequeue(out var item); // Assert Assert.False(queue.Contains(1)); } #endregion TryDequeue 方法测试 #region TryPeek 方法测试 [Fact] public void TryPeek_ReturnsTrueAndItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.TryPeek(out var item); // Assert Assert.True(result); Assert.Equal(1, item); } [Fact] public void TryPeek_ReturnsFalseWhenEmpty() { // Arrange var queue = new ConcurrentHashQueue(); // Act var result = queue.TryPeek(out var item); // Assert Assert.False(result); Assert.Equal(default(int), item); } [Fact] public void TryPeek_DoesNotRemoveItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act queue.TryPeek(out var item); // Assert Assert.Equal(3, queue.Count); Assert.Contains(1, queue); } [Fact] public void TryPeek_MultipleCallsReturnSameItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act queue.TryPeek(out var first); queue.TryPeek(out var second); // Assert Assert.Equal(first, second); Assert.Equal(3, queue.Count); } #endregion TryPeek 方法测试 #region Contains 方法测试 [Fact] public void Contains_ReturnsTrueForExistingItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.Contains(2); // Assert Assert.True(result); } [Fact] public void Contains_ReturnsFalseForNonExistingItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.Contains(4); // Assert Assert.False(result); } [Fact] public void Contains_ReturnsFalseForRemovedItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act queue.TryDequeue(out _); var result = queue.Contains(1); // Assert Assert.False(result); } #endregion Contains 方法测试 #region Add 方法测试 [Fact] public void Add_AddsItem() { // Arrange var queue = new ConcurrentHashQueue(); // Act queue.Add(1); // Assert Assert.Single(queue); Assert.Contains(1, queue); } [Fact] public void Add_DoesNotThrowOnDuplicate() { // Arrange var queue = new ConcurrentHashQueue(); queue.Add(1); // Act & Assert (should not throw) queue.Add(1); } #endregion Add 方法测试 #region Clear 方法测试 [Fact] public void Clear_RemovesAllItems() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act queue.Clear(); // Assert Assert.Empty(queue); Assert.Equal(0, queue.Count); Assert.True(queue.IsEmpty); } [Fact] public void Clear_AllowsReenqueueAfterClear() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); queue.Clear(); // Act queue.Enqueue(4); // Assert Assert.Single(queue); Assert.Contains(4, queue); } #endregion Clear 方法测试 #region Remove 方法测试 [Fact] public void Remove_RemovesSpecificItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.Remove(2); // Assert Assert.True(result); Assert.Equal(2, queue.Count); Assert.DoesNotContain(2, queue); Assert.Contains(1, queue); Assert.Contains(3, queue); } [Fact] public void Remove_ReturnsFalseForNonExistingItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.Remove(4); // Assert Assert.False(result); Assert.Equal(3, queue.Count); } [Fact] public void Remove_MaintainsRemainingItemsOrder() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3, 4, 5 }); // Act queue.Remove(3); // Assert var array = queue.ToArray(); Assert.Equal(new[] { 1, 2, 4, 5 }, array); } [Fact] public void Remove_RemovesFirstOccurrenceOnly() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.Remove(1); // Assert Assert.True(result); Assert.DoesNotContain(1, queue); } #endregion Remove 方法测试 #region 属性测试 [Fact] public void Count_ReturnsCorrectCount() { // Arrange var queue = new ConcurrentHashQueue(); // Act & Assert Assert.Equal(0, queue.Count); queue.Enqueue(1); Assert.Equal(1, queue.Count); queue.Enqueue(2); Assert.Equal(2, queue.Count); queue.TryDequeue(out _); Assert.Equal(1, queue.Count); } [Fact] public void IsEmpty_ReturnsTrueForEmptyQueue() { // Arrange var queue = new ConcurrentHashQueue(); // Act & Assert Assert.True(queue.IsEmpty); } [Fact] public void IsEmpty_ReturnsFalseForNonEmptyQueue() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1 }); // Act & Assert Assert.False(queue.IsEmpty); } [Fact] public void IsReadOnly_ReturnsFalse() { // Arrange var queue = new ConcurrentHashQueue(); // Act var isReadOnly = queue.IsReadOnly; // Assert Assert.False(isReadOnly); } #endregion 属性测试 #region ToArray 方法测试 [Fact] public void ToArray_ReturnsArrayWithAllItems() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var array = queue.ToArray(); // Assert Assert.Equal(3, array.Length); Assert.Equal(new[] { 1, 2, 3 }, array); } [Fact] public void ToArray_ReturnsEmptyArrayForEmptyQueue() { // Arrange var queue = new ConcurrentHashQueue(); // Act var array = queue.ToArray(); // Assert Assert.Empty(array); } [Fact] public void ToArray_ReturnsItemsInQueueOrder() { // Arrange var queue = new ConcurrentHashQueue(); queue.Enqueue(5); queue.Enqueue(3); queue.Enqueue(8); // Act var array = queue.ToArray(); // Assert Assert.Equal(new[] { 5, 3, 8 }, array); } #endregion ToArray 方法测试 #region CopyTo 方法测试 [Fact] public void CopyTo_CopiesItemsToArray() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); var targetArray = new int[5]; // Act queue.CopyTo(targetArray, 0); // Assert Assert.Equal(1, targetArray[0]); Assert.Equal(2, targetArray[1]); Assert.Equal(3, targetArray[2]); Assert.Equal(0, targetArray[3]); Assert.Equal(0, targetArray[4]); } [Fact] public void CopyTo_CopiesItemsWithOffset() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); var targetArray = new int[5]; // Act queue.CopyTo(targetArray, 1); // Assert Assert.Equal(0, targetArray[0]); Assert.Equal(1, targetArray[1]); Assert.Equal(2, targetArray[2]); Assert.Equal(3, targetArray[3]); Assert.Equal(0, targetArray[4]); } [Fact] public void CopyTo_WithNullArray_ThrowsArgumentNullException() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act & Assert Assert.Throws(() => queue.CopyTo(null, 0)); } [Fact] public void CopyTo_WithNegativeIndex_ThrowsArgumentOutOfRangeException() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); var targetArray = new int[5]; // Act & Assert Assert.Throws(() => queue.CopyTo(targetArray, -1)); } [Fact] public void CopyTo_WithInsufficientSpace_ThrowsArgumentException() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); var targetArray = new int[2]; // Act & Assert Assert.Throws(() => queue.CopyTo(targetArray, 0)); } #endregion CopyTo 方法测试 #region 集合接口测试 [Fact] public void IEnumerable_CanIterateOverItems() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); var items = new List(); // Act foreach (var item in queue) { items.Add(item); } // Assert Assert.Equal(new[] { 1, 2, 3 }, items); } [Fact] public void IProducerConsumerCollection_TryAdd_AddsItem() { // Arrange var queue = new ConcurrentHashQueue(); IProducerConsumerCollection collection = queue; // Act var result = collection.TryAdd(1); // Assert Assert.True(result); Assert.Single(queue); } [Fact] public void IProducerConsumerCollection_TryTake_RemovesItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); IProducerConsumerCollection collection = queue; // Act var result = collection.TryTake(out var item); // Assert Assert.True(result); Assert.Equal(1, item); Assert.Equal(2, queue.Count); } #endregion 集合接口测试 #region EnqueueRange 方法测试 [Fact] public void EnqueueRange_AddsMultipleItems() { // Arrange var queue = new ConcurrentHashQueue(); var items = new[] { 1, 2, 3, 4, 5 }; // Act var count = queue.EnqueueRange(items); // Assert Assert.Equal(5, count); Assert.Equal(5, queue.Count); } [Fact] public void EnqueueRange_IgnoresDuplicates() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2 }); var items = new[] { 2, 3, 4 }; // Act var count = queue.EnqueueRange(items); // Assert Assert.Equal(2, count); Assert.Equal(4, queue.Count); Assert.True(queue.Contains(1)); Assert.True(queue.Contains(2)); Assert.True(queue.Contains(3)); Assert.True(queue.Contains(4)); } [Fact] public void EnqueueRange_WithNullCollection_ThrowsArgumentNullException() { // Arrange var queue = new ConcurrentHashQueue(); // Act & Assert Assert.Throws(() => queue.EnqueueRange(null)); } [Fact] public void EnqueueRange_WithEmptyCollection_ReturnsZero() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); var items = new int[] { }; // Act var count = queue.EnqueueRange(items); // Assert Assert.Equal(0, count); Assert.Equal(3, queue.Count); } #endregion EnqueueRange 方法测试 #region DequeueRange 方法测试 [Fact] public void DequeueRange_RemovesMultipleItems() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3, 4, 5 }); // Act var items = queue.DequeueRange(3).ToList(); // Assert Assert.Equal(3, items.Count); Assert.Equal(new[] { 1, 2, 3 }, items); Assert.Equal(2, queue.Count); } [Fact] public void DequeueRange_WithCountGreaterThanQueueSize_RemovesAllItems() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var items = queue.DequeueRange(10).ToList(); // Assert Assert.Equal(3, items.Count); Assert.Empty(queue); } [Fact] public void DequeueRange_WithZeroCount_ReturnsEmptyCollection() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var items = queue.DequeueRange(0).ToList(); // Assert Assert.Empty(items); Assert.Equal(3, queue.Count); } [Fact] public void DequeueRange_WithNegativeCount_ThrowsArgumentOutOfRangeException() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act & Assert Assert.Throws(() => queue.DequeueRange(-1)); } [Fact] public void DequeueRange_RemovesItemsInFifoOrder() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3, 4, 5 }); // Act var items = queue.DequeueRange(3).ToList(); // Assert Assert.Equal(1, items[0]); Assert.Equal(2, items[1]); Assert.Equal(3, items[2]); } #endregion DequeueRange 方法测试 #region TryEnqueueWithLimit 方法测试 [Fact] public void TryEnqueueWithLimit_AddsItemWhenBelowLimit() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2 }); // Act var result = queue.TryEnqueueWithLimit(3, 5); // Assert Assert.True(result); Assert.Equal(3, queue.Count); Assert.Contains(3, queue); } [Fact] public void TryEnqueueWithLimit_ReturnsFalseWhenAtLimitWithNewItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.TryEnqueueWithLimit(4, 3); // Assert Assert.False(result); Assert.Equal(3, queue.Count); Assert.DoesNotContain(4, queue); } [Fact] public void TryEnqueueWithLimit_AddsExistingItemWhenAtLimit() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var result = queue.TryEnqueueWithLimit(1, 3); // Assert Assert.False(result); Assert.Equal(3, queue.Count); } [Fact] public void TryEnqueueWithLimit_WithInvalidLimit_ThrowsArgumentOutOfRangeException() { // Arrange var queue = new ConcurrentHashQueue(); // Act & Assert Assert.Throws(() => queue.TryEnqueueWithLimit(1, 0)); Assert.Throws(() => queue.TryEnqueueWithLimit(1, -1)); } #endregion TryEnqueueWithLimit 方法测试 #region EnqueueWithEviction 方法测试 [Fact] public void EnqueueWithEviction_AddsItemWhenBelowLimit() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2 }); // Act var evicted = queue.EnqueueWithEviction(3, 5); // Assert Assert.Equal(default(int), evicted); Assert.Equal(3, queue.Count); Assert.Contains(3, queue); } [Fact] public void EnqueueWithEviction_EvictsOldestWhenAtLimit() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var evicted = queue.EnqueueWithEviction(4, 3); // Assert Assert.Equal(1, evicted); Assert.Equal(3, queue.Count); Assert.Contains(2, queue); Assert.Contains(3, queue); Assert.Contains(4, queue); Assert.DoesNotContain(1, queue); } [Fact] public void EnqueueWithEviction_RequeuesExistingItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); // Act var evicted = queue.EnqueueWithEviction(2, 3); // Assert Assert.Equal(default(int), evicted); Assert.Equal(3, queue.Count); var array = queue.ToArray(); // Item 2 should be moved to the end Assert.Equal(2, array[2]); } [Fact] public void EnqueueWithEviction_WithInvalidLimit_ThrowsArgumentOutOfRangeException() { // Arrange var queue = new ConcurrentHashQueue(); // Act & Assert Assert.Throws(() => queue.EnqueueWithEviction(1, 0)); } #endregion EnqueueWithEviction 方法测试 #region 并发操作测试 [Fact] public void ConcurrentEnqueue_MultipleThreads_AllItemsAdded() { // Arrange var queue = new ConcurrentHashQueue(); var tasks = new Task[10]; // Act for (int i = 0; i < 10; i++) { int value = i; tasks[i] = Task.Run(() => queue.Enqueue(value)); } Task.WaitAll(tasks); // Assert Assert.Equal(10, queue.Count); } [Fact] public void ConcurrentDequeue_MultipleThreads_AllItemsRemoved() { // Arrange var queue = new ConcurrentHashQueue(Enumerable.Range(1, 10).ToArray()); var tasks = new Task[10]; var results = new List(); var lockObj = new object(); // Act for (int i = 0; i < 10; i++) { tasks[i] = Task.Run(() => { if (queue.TryDequeue(out var item)) { lock (lockObj) { results.Add(item); } } }); } Task.WaitAll(tasks); // Assert Assert.Equal(10, results.Count); Assert.Empty(queue); } [Fact] public void ConcurrentEnqueueWithDuplicates_OnlyUniqueItemsAdded() { // Arrange var queue = new ConcurrentHashQueue(); var tasks = new Task[10]; // Act - All threads try to enqueue the same values for (int t = 0; t < 10; t++) { int threadId = t; tasks[t] = Task.Run(() => { for (int i = 0; i < 5; i++) { queue.Enqueue(i); } }); } Task.WaitAll(tasks); // Assert - Only 5 unique items should be in queue Assert.Equal(5, queue.Count); } [Fact] public void ConcurrentRemove_WhileEnqueuing() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3, 4, 5 }); // Act - Enqueue and Remove concurrently var enqueueTask = Task.Run(() => { for (int i = 6; i < 15; i++) { queue.Enqueue(i); } }); var removeTask = Task.Run(() => { for (int i = 1; i < 6; i++) { queue.Remove(i); Thread.Sleep(10); } }); Task.WaitAll(enqueueTask, removeTask); // Assert - Queue should have items from 6 to 14 Assert.Equal(9, queue.Count); for (int i = 6; i < 15; i++) { Assert.Contains(i, queue); } } #endregion 并发操作测试 #region ICollection 接口测试 [Fact] public void ICollection_CopyTo_CopiesItems() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3 }); System.Collections.ICollection collection = queue; var array = new object[5]; // Act collection.CopyTo(array, 0); // Assert Assert.Equal(1, (int)array[0]); Assert.Equal(2, (int)array[1]); Assert.Equal(3, (int)array[2]); } [Fact] public void ICollection_IsSynchronized_ReturnsFalse() { // Arrange var queue = new ConcurrentHashQueue(); System.Collections.ICollection collection = queue; // Act var isSynchronized = collection.IsSynchronized; // Assert Assert.False(isSynchronized); } [Fact] public void ICollection_SyncRoot_ReturnsNonNull() { // Arrange var queue = new ConcurrentHashQueue(); System.Collections.ICollection collection = queue; // Act var syncRoot = collection.SyncRoot; // Assert Assert.NotNull(syncRoot); } #endregion ICollection 接口测试 #region 综合场景测试 [Fact] public void ComplexScenario_MixedOperations() { // Arrange var queue = new ConcurrentHashQueue(new[] { "a", "b", "c" }); // Act & Assert Assert.Equal(3, queue.Count); queue.Add("d"); Assert.Equal(4, queue.Count); queue.TryPeek(out var peeked); Assert.Equal("a", peeked); Assert.Equal(4, queue.Count); queue.TryDequeue(out var dequeued); Assert.Equal("a", dequeued); Assert.Equal(3, queue.Count); queue.Add("e"); queue.Add("b"); // Duplicate, silently ignored Assert.Equal(4, queue.Count); queue.Remove("c"); Assert.False(queue.Contains("c")); Assert.Equal(3, queue.Count); queue.Clear(); Assert.True(queue.IsEmpty); } [Fact] public void ComplexScenario_EnqueueAndDequeueWithDuplicates() { // Arrange var queue = new ConcurrentHashQueue(); // Act queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(1); // Duplicate queue.Enqueue(3); queue.Enqueue(2); // Duplicate // Assert Assert.Equal(3, queue.Count); queue.TryDequeue(out var first); queue.TryDequeue(out var second); queue.TryDequeue(out var third); Assert.Equal(1, first); Assert.Equal(2, second); Assert.Equal(3, third); Assert.True(queue.IsEmpty); } [Fact] public void ComplexScenario_RemoveMiddleItem() { // Arrange var queue = new ConcurrentHashQueue(new[] { 1, 2, 3, 4, 5 }); // Act queue.Remove(3); // Assert Assert.Equal(4, queue.Count); var array = queue.ToArray(); Assert.Equal(new[] { 1, 2, 4, 5 }, array); } #endregion 综合场景测试 #region 自定义比较器测试 [Fact] public void WithCustomComparer_IgnoresDuplicatesAccordingToComparer() { // Arrange var comparer = new AbsoluteValueComparer(); var queue = new ConcurrentHashQueue(comparer); // Act var result1 = queue.Enqueue(5); var result2 = queue.Enqueue(-5); // Assert Assert.True(result1); Assert.False(result2); Assert.Single(queue); } #endregion 自定义比较器测试 }