mirror of
https://github.com/ldqk/Masuit.Tools.git
synced 2026-10-27 11:16:34 +08:00
全面用SkiaSharp替换ImageSharp进行图像处理,包括哈希、边框检测、水印、验证码、图片工具等模块。重构IImageTransformer及相关接口和实现,调整测试用例以适配SkiaSharp。移除ImageSharp依赖,新增SkiaSharp依赖。同步升级部分依赖包版本。优化部分算法性能,提升跨平台兼容性。
1192 lines
28 KiB
C#
1192 lines
28 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// ConcurrentHashQueue<T> 的单元测试类
|
|
/// </summary>
|
|
public class ConcurrentHashQueueTests
|
|
{
|
|
#region 构造函数测试
|
|
|
|
[Fact]
|
|
public void Constructor_Default_CreatesEmptyQueue()
|
|
{
|
|
// Arrange & Act
|
|
var queue = new ConcurrentHashQueue<int>();
|
|
|
|
// Assert
|
|
Assert.Empty(queue);
|
|
Assert.Equal(0, queue.Count);
|
|
Assert.True(queue.IsEmpty);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_WithComparer_UsesProvidedComparer()
|
|
{
|
|
// Arrange
|
|
var comparer = EqualityComparer<int>.Default;
|
|
|
|
// Act
|
|
var queue = new ConcurrentHashQueue<int>(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<int>(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<int>.Default;
|
|
|
|
// Act
|
|
var queue = new ConcurrentHashQueue<int>(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<int>(items);
|
|
|
|
// Assert
|
|
Assert.Equal(3, queue.Count);
|
|
}
|
|
|
|
#endregion 构造函数测试
|
|
|
|
#region Enqueue 方法测试
|
|
|
|
[Fact]
|
|
public void Enqueue_AddsSingleItem()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>();
|
|
|
|
// 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<int>();
|
|
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<int>();
|
|
|
|
// 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<int>();
|
|
|
|
// 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<int>(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<int>();
|
|
|
|
// 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<int>(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<int>(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<int>(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<int>();
|
|
|
|
// 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<int>(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<int>(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<int>(new[] { 1, 2, 3 });
|
|
|
|
// Act
|
|
var result = queue.Contains(2);
|
|
|
|
// Assert
|
|
Assert.True(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void Contains_ReturnsFalseForNonExistingItem()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(new[] { 1, 2, 3 });
|
|
|
|
// Act
|
|
var result = queue.Contains(4);
|
|
|
|
// Assert
|
|
Assert.False(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void Contains_ReturnsFalseForRemovedItem()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(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<int>();
|
|
|
|
// Act
|
|
queue.Add(1);
|
|
|
|
// Assert
|
|
Assert.Single(queue);
|
|
Assert.Contains(1, queue);
|
|
}
|
|
|
|
[Fact]
|
|
public void Add_DoesNotThrowOnDuplicate()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>();
|
|
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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>();
|
|
|
|
// 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<int>();
|
|
|
|
// Act & Assert
|
|
Assert.True(queue.IsEmpty);
|
|
}
|
|
|
|
[Fact]
|
|
public void IsEmpty_ReturnsFalseForNonEmptyQueue()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(new[] { 1 });
|
|
|
|
// Act & Assert
|
|
Assert.False(queue.IsEmpty);
|
|
}
|
|
|
|
[Fact]
|
|
public void IsReadOnly_ReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>();
|
|
|
|
// Act
|
|
var isReadOnly = queue.IsReadOnly;
|
|
|
|
// Assert
|
|
Assert.False(isReadOnly);
|
|
}
|
|
|
|
#endregion 属性测试
|
|
|
|
#region ToArray 方法测试
|
|
|
|
[Fact]
|
|
public void ToArray_ReturnsArrayWithAllItems()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(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<int>();
|
|
|
|
// Act
|
|
var array = queue.ToArray();
|
|
|
|
// Assert
|
|
Assert.Empty(array);
|
|
}
|
|
|
|
[Fact]
|
|
public void ToArray_ReturnsItemsInQueueOrder()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>();
|
|
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<int>(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<int>(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<int>(new[] { 1, 2, 3 });
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>(() => queue.CopyTo(null, 0));
|
|
}
|
|
|
|
[Fact]
|
|
public void CopyTo_WithNegativeIndex_ThrowsArgumentOutOfRangeException()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(new[] { 1, 2, 3 });
|
|
var targetArray = new int[5];
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => queue.CopyTo(targetArray, -1));
|
|
}
|
|
|
|
[Fact]
|
|
public void CopyTo_WithInsufficientSpace_ThrowsArgumentException()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(new[] { 1, 2, 3 });
|
|
var targetArray = new int[2];
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentException>(() => queue.CopyTo(targetArray, 0));
|
|
}
|
|
|
|
#endregion CopyTo 方法测试
|
|
|
|
#region 集合接口测试
|
|
|
|
[Fact]
|
|
public void IEnumerable_CanIterateOverItems()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(new[] { 1, 2, 3 });
|
|
var items = new List<int>();
|
|
|
|
// 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<int>();
|
|
IProducerConsumerCollection<int> 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<int>(new[] { 1, 2, 3 });
|
|
IProducerConsumerCollection<int> 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<int>();
|
|
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<int>(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<int>();
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>(() => queue.EnqueueRange(null));
|
|
}
|
|
|
|
[Fact]
|
|
public void EnqueueRange_WithEmptyCollection_ReturnsZero()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(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<int>(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<int>(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<int>(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<int>(new[] { 1, 2, 3 });
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => queue.DequeueRange(-1));
|
|
}
|
|
|
|
[Fact]
|
|
public void DequeueRange_RemovesItemsInFifoOrder()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(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<int>(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<int>(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<int>(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<int>();
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => queue.TryEnqueueWithLimit(1, 0));
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => queue.TryEnqueueWithLimit(1, -1));
|
|
}
|
|
|
|
#endregion TryEnqueueWithLimit 方法测试
|
|
|
|
#region EnqueueWithEviction 方法测试
|
|
|
|
[Fact]
|
|
public void EnqueueWithEviction_AddsItemWhenBelowLimit()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>(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<int>(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<int>(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<int>();
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => queue.EnqueueWithEviction(1, 0));
|
|
}
|
|
|
|
#endregion EnqueueWithEviction 方法测试
|
|
|
|
#region 并发操作测试
|
|
|
|
[Fact]
|
|
public void ConcurrentEnqueue_MultipleThreads_AllItemsAdded()
|
|
{
|
|
// Arrange
|
|
var queue = new ConcurrentHashQueue<int>();
|
|
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<int>(Enumerable.Range(1, 10).ToArray());
|
|
var tasks = new Task[10];
|
|
var results = new List<int>();
|
|
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<int>();
|
|
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<int>(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<int>(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<int>();
|
|
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<int>();
|
|
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<string>(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<int>();
|
|
|
|
// 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<int>(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<int>(comparer);
|
|
|
|
// Act
|
|
var result1 = queue.Enqueue(5);
|
|
var result2 = queue.Enqueue(-5);
|
|
|
|
// Assert
|
|
Assert.True(result1);
|
|
Assert.False(result2);
|
|
Assert.Single(queue);
|
|
}
|
|
|
|
#endregion 自定义比较器测试
|
|
} |