public async Task ShouldWaitAndRelease(SemaphoreSlimLock sut)
    {
        var mutex = GetSemaphore(sut);

        Assert.Equal(1, mutex.CurrentCount);

        await sut.WaitAsync(Cts.Token);

        Assert.Equal(0, mutex.CurrentCount);

        var second = sut.WaitAsync(Cts.Token);

        await Wait();

        Assert.False(second.IsCompleted);
        Assert.Equal(0, mutex.CurrentCount);

        await sut.ReleaseAsync(Cts.Token);

        await second;

        Assert.True(second.IsCompletedSuccessfully);
        Assert.Equal(0, mutex.CurrentCount);

        await sut.ReleaseAsync(Cts.Token);

        Assert.Equal(1, mutex.CurrentCount);

        await AssertThrowsAsync <SemaphoreFullException>(
            () => sut.ReleaseAsync(Cts.Token));
    }
    public async Task ReleaseAsync_ShouldThrowIfDisposed(SemaphoreSlimLock sut)
    {
        sut.Dispose();

        var exception = await AssertThrowsAsync <ObjectDisposedException>(
            () => sut.ReleaseAsync(Cts.Token));

        Assert.Equal(typeof(SemaphoreSlimLock).FullName, exception.ObjectName);
    }