From 281c591b6445f0ccb4a74c307702709743eca81a Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Sat, 30 Dec 2023 11:17:35 +0100 Subject: [PATCH] Code coverage --- .../StripedAsyncKeyedLocker/OriginalTests.cs | 277 ++++++++++++++---- 1 file changed, 212 insertions(+), 65 deletions(-) diff --git a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs index 697fa16..2a10e10 100644 --- a/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs +++ b/AsyncKeyedLock.Tests/StripedAsyncKeyedLocker/OriginalTests.cs @@ -61,113 +61,260 @@ public void TestHashHelpersIsPrime2() HashHelpers.IsPrime(2).Should().Be(true); } + [Fact] + public void TestComparerShouldBePossible() + { + Action action = () => + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(comparer: EqualityComparer.Default); + }; + action.Should().NotThrow(); + } + + [Fact] + public void TestComparerAndMaxCount1ShouldBePossible() + { + Action action = () => + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(maxCount: 1, comparer: EqualityComparer.Default); + }; + action.Should().NotThrow(); + } + + [Fact] + public void TestComparerAndMaxCount0ShouldNotBePossible() + { + Action action = () => + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(maxCount: 0, comparer: EqualityComparer.Default); + }; + action.Should().Throw(); + } + + [Fact] + public void TestNumberOfStripesShouldBePossible() + { + Action action = () => + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(Environment.ProcessorCount); + }; + action.Should().NotThrow(); + } + + [Fact] + public void TestMaxCount0WithNumberOfStripesShouldNotBePossible() + { + Action action = () => + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(numberOfStripes: 42, maxCount: 0); + }; + action.Should().Throw(); + } + + [Fact] + public void TestReadingMaxCount() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(maxCount: 2); + stripedAsyncKeyedLocker.MaxCount.Should().Be(2); + } + + [Fact] + public void TestReadingMaxCountViaParameterWithComparer() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(maxCount: 2, comparer: EqualityComparer.Default); + stripedAsyncKeyedLocker.MaxCount.Should().Be(2); + } + + [Fact] + public void TestReadingMaxCountViaParameterWithNumberOfStripes() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(42, 2); + stripedAsyncKeyedLocker.MaxCount.Should().Be(2); + } + + [Fact] + public void TestReadingMaxCountViaParameterWithNumberOfStripesAndComparer() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(42, 2, EqualityComparer.Default); + stripedAsyncKeyedLocker.MaxCount.Should().Be(2); + } + [Fact] public async Task TestTimeoutBasic() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (var myLock = await asyncKeyedLocker.LockAsync("test", 0)) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (var myLock = await stripedAsyncKeyedLocker.LockAsync("test", 0)) { Assert.True(myLock.EnteredSemaphore); - Assert.True(asyncKeyedLocker.IsInUse("test")); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] public void TestTimeoutBasicWithOutParameter() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (var myLock = asyncKeyedLocker.Lock("test", 0, out bool entered)) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (var myLock = stripedAsyncKeyedLocker.Lock("test", 0, out var entered)) { Assert.True(entered); - Assert.True(asyncKeyedLocker.IsInUse("test")); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] public async Task TestTimeout() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (await asyncKeyedLocker.LockAsync("test", 0)) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (await stripedAsyncKeyedLocker.LockAsync("test")) { - using (var myLock = await asyncKeyedLocker.LockAsync("test", 0)) + using (var myLock = await stripedAsyncKeyedLocker.LockAsync("test", 0)) { Assert.False(myLock.EnteredSemaphore); } - Assert.True(asyncKeyedLocker.IsInUse("test")); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] public void TestTimeoutWithTimeSpanSynchronous() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (asyncKeyedLocker.Lock("test", TimeSpan.Zero, out bool entered)) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test")) { - Assert.True(entered); - using (asyncKeyedLocker.Lock("test", TimeSpan.Zero, out entered)) + using (stripedAsyncKeyedLocker.Lock("test", TimeSpan.Zero, out bool entered)) { Assert.False(entered); } - Assert.True(asyncKeyedLocker.IsInUse("test")); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); + } + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); + } + + [Fact] + public void TestTimeoutWithInfiniteTimeoutSynchronous() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test", Timeout.Infinite, out bool entered)) + { + Assert.True(entered); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] - public void TestTimeoutWithTimeoutSynchronous() + public void TestTimeoutWithInfiniteTimeSpanSynchronous() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (asyncKeyedLocker.Lock("test")) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test", TimeSpan.FromMilliseconds(Timeout.Infinite), out bool entered)) { - using (asyncKeyedLocker.Lock("test", 0, out bool entered)) + Assert.True(entered); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); + } + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); + } + + [Fact] + public async Task TestTimeoutWithTimeSpan() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (await stripedAsyncKeyedLocker.LockAsync("test")) + { + using (var myLock = await stripedAsyncKeyedLocker.LockAsync("test", TimeSpan.Zero)) { - Assert.False(entered); + Assert.False(myLock.EnteredSemaphore); } - Assert.True(asyncKeyedLocker.IsInUse("test")); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] - public void TestTimeoutWithInfiniteTimeoutSynchronous() + public void TestTimeoutWithInfiniteTimeoutAndCancellationToken() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (asyncKeyedLocker.Lock("test", Timeout.Infinite, out bool entered)) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test", Timeout.Infinite, new CancellationToken(false), out bool entered)) { Assert.True(entered); - Assert.True(asyncKeyedLocker.IsInUse("test")); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] - public void TestTimeoutWithInfiniteTimeSpanSynchronous() + public void TestTimeoutWithZeroTimeoutAndCancellationToken() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (asyncKeyedLocker.Lock("test", TimeSpan.FromMilliseconds(Timeout.Infinite), out bool entered)) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test", 0, new CancellationToken(false), out bool entered)) { Assert.True(entered); - Assert.True(asyncKeyedLocker.IsInUse("test")); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] - public async Task TestTimeoutWithTimeSpan() + public void TestTimeoutWithZeroTimeoutAndCancelledToken() { - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); - using (await asyncKeyedLocker.LockAsync("test")) + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + Action action = () => { - using (var myLock = await asyncKeyedLocker.LockAsync("test", TimeSpan.Zero)) - { - Assert.False(myLock.EnteredSemaphore); - } - Assert.True(asyncKeyedLocker.IsInUse("test")); + stripedAsyncKeyedLocker.Lock("test", 0, new CancellationToken(true), out bool entered); + }; + action.Should().Throw(); + stripedAsyncKeyedLocker.IsInUse("test").Should().BeFalse(); + } + + [Fact] + public void TestTimeoutWithInfiniteTimeSpanAndCancellationToken() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test", TimeSpan.FromMilliseconds(Timeout.Infinite), new CancellationToken(false), out bool entered)) + { + Assert.True(entered); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); + } + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); + } + + [Fact] + public void TestTimeoutWithZeroTimeSpanAndCancellationToken() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test", TimeSpan.FromMilliseconds(0), new CancellationToken(false), out bool entered)) + { + Assert.True(entered); + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); + } + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); + } + + [Fact] + public void TestTimeoutWithZeroTimeSpanAndCancelledToken() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + Action action = () => + { + stripedAsyncKeyedLocker.Lock("test", TimeSpan.FromMilliseconds(0), new CancellationToken(true), out bool entered); + }; + action.Should().Throw(); + stripedAsyncKeyedLocker.IsInUse("test").Should().BeFalse(); + } + + [Fact] + public void TestTimeoutTryLock() + { + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); + using (stripedAsyncKeyedLocker.Lock("test")) + { + Assert.True(stripedAsyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.TryLock("test", () => { }, 0, CancellationToken.None)); + Assert.False(stripedAsyncKeyedLocker.TryLock("test", () => { }, TimeSpan.Zero, CancellationToken.None)); } - Assert.False(asyncKeyedLocker.IsInUse("test")); + Assert.False(stripedAsyncKeyedLocker.IsInUse("test")); } [Fact] @@ -175,14 +322,14 @@ public async Task BasicTest() { var locks = 5000; var concurrency = 50; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); var concurrentQueue = new ConcurrentQueue<(bool entered, int key)>(); var tasks = Enumerable.Range(1, locks * concurrency) .Select(async i => { var key = Convert.ToInt32(Math.Ceiling((double)i / concurrency)); - using (await asyncKeyedLocker.LockAsync(key)) + using (await stripedAsyncKeyedLocker.LockAsync(key)) { await Task.Delay(20); concurrentQueue.Enqueue((true, key)); @@ -227,14 +374,14 @@ public async Task BasicTestGenerics() { var locks = 5000; var concurrency = 50; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); var concurrentQueue = new ConcurrentQueue<(bool entered, int key)>(); var tasks = Enumerable.Range(1, locks * concurrency) .Select(async i => { var key = Convert.ToInt32(Math.Ceiling((double)i / concurrency)); - using (await asyncKeyedLocker.LockAsync(key)) + using (await stripedAsyncKeyedLocker.LockAsync(key)) { await Task.Delay(20); concurrentQueue.Enqueue((true, key)); @@ -328,14 +475,14 @@ public async Task BasicTestGenericsString() { var locks = 5000; var concurrency = 50; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); var concurrentQueue = new ConcurrentQueue<(bool entered, string key)>(); var tasks = Enumerable.Range(1, locks * concurrency) .Select(async i => { var key = Convert.ToInt32(Math.Ceiling((double)i / 5)).ToString(); - using (await asyncKeyedLocker.LockAsync(key)) + using (await stripedAsyncKeyedLocker.LockAsync(key)) { await Task.Delay(20); concurrentQueue.Enqueue((true, key)); @@ -379,7 +526,7 @@ public async Task BasicTestGenericsString() public async Task Test1AtATime() { var range = 25000; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); var concurrentQueue = new ConcurrentQueue(); int threadNum = 0; @@ -388,7 +535,7 @@ public async Task Test1AtATime() .Select(async i => { var key = Convert.ToInt32(Math.Ceiling((double)Interlocked.Increment(ref threadNum) / 2)); - using (await asyncKeyedLocker.LockAsync(key)) + using (await stripedAsyncKeyedLocker.LockAsync(key)) { concurrentQueue.Enqueue(key); } @@ -414,14 +561,14 @@ public async Task Test1AtATime() public async Task Test2AtATime() { var range = 4; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(maxCount: 2); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(o => o.MaxCount = 2); var concurrentQueue = new ConcurrentQueue(); var tasks = Enumerable.Range(1, range * 4) .Select(async i => { var key = Convert.ToInt32(Math.Ceiling((double)i / 4)); - using (await asyncKeyedLocker.LockAsync(key)) + using (await stripedAsyncKeyedLocker.LockAsync(key)) { concurrentQueue.Enqueue(key); await Task.Delay((100 * key) + 1000); @@ -448,7 +595,7 @@ public async Task Test2AtATime() public async Task Test1AtATimeGenerics() { var range = 25000; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); var concurrentQueue = new ConcurrentQueue(); int threadNum = 0; @@ -457,7 +604,7 @@ public async Task Test1AtATimeGenerics() .Select(async i => { var key = Convert.ToInt32(Math.Ceiling((double)Interlocked.Increment(ref threadNum) / 2)); - using (await asyncKeyedLocker.LockAsync(key)) + using (await stripedAsyncKeyedLocker.LockAsync(key)) { concurrentQueue.Enqueue(key); } @@ -483,14 +630,14 @@ public async Task Test1AtATimeGenerics() public async Task Test2AtATimeGenerics() { var range = 4; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(maxCount: 2); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(o => o.MaxCount = 2); var concurrentQueue = new ConcurrentQueue(); var tasks = Enumerable.Range(1, range * 4) .Select(async i => { var key = Convert.ToInt32(Math.Ceiling((double)i / 4)); - using (await asyncKeyedLocker.LockAsync(key)) + using (await stripedAsyncKeyedLocker.LockAsync(key)) { concurrentQueue.Enqueue(key); await Task.Delay((100 * key) + 1000); @@ -525,7 +672,7 @@ private async Task TestContinueOnCapturedContext(bool continueOnCapturedContext) { const string Key = "test"; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); var testContext = new TestSynchronizationContext(); void Callback() @@ -546,7 +693,7 @@ void Callback() try { // This is just to make WaitAsync in TryLockAsync not finish synchronously - var obj = asyncKeyedLocker.Lock(Key); + var obj = stripedAsyncKeyedLocker.Lock(Key); _ = Task.Run(async () => { @@ -554,7 +701,7 @@ void Callback() obj.Dispose(); }); - await asyncKeyedLocker.TryLockAsync(Key, Callback, 5000, continueOnCapturedContext); + await stripedAsyncKeyedLocker.TryLockAsync(Key, Callback, 5000, continueOnCapturedContext); } finally { @@ -574,7 +721,7 @@ private async Task TestConfigureAwaitOptions(ConfigureAwaitOptions configureAwai { const string Key = "test"; - var asyncKeyedLocker = new StripedAsyncKeyedLocker(); + var stripedAsyncKeyedLocker = new StripedAsyncKeyedLocker(); var testContext = new TestSynchronizationContext(); void Callback() @@ -595,7 +742,7 @@ void Callback() try { // This is just to make WaitAsync in TryLockAsync not finish synchronously - var obj = asyncKeyedLocker.Lock(Key); + var obj = stripedAsyncKeyedLocker.Lock(Key); _ = Task.Run(async () => { @@ -603,7 +750,7 @@ void Callback() obj.Dispose(); }); - await asyncKeyedLocker.TryLockAsync(Key, Callback, 5000, configureAwaitOptions); + await stripedAsyncKeyedLocker.TryLockAsync(Key, Callback, 5000, configureAwaitOptions); } finally {