Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -494,74 +494,84 @@ private void EnsureCapacity_Zero_NoChange()
Assert.Equal(currentCapacity, builder.Capacity);
}

// The growth tests below assert an inequality. EnsureCapacity rents from ArrayPool and
// promises only that the buffer is at least as large as requested; any doubling is the
// pool's bucket rounding, not something OperationBuilder implements. Asserting an exact
// size makes these depend on pool internals, which on .NET Framework overshoot to a larger
// bucket when the requested one is exhausted.

[Fact]
private void EnsureCapacity_OneMore_Doubles()
private void EnsureCapacity_OneMore_Grows()
{
// Arrange

using var builder = new OperationBuilder();
var currentCapacity = builder.Capacity;
var requested = builder.Capacity + 1;

// Act

builder.EnsureCapacity(currentCapacity + 1);
builder.EnsureCapacity(requested);

// Assert

Assert.Equal(currentCapacity * 2, builder.Capacity);
AssertAtLeast(requested, builder.Capacity);
}

[Fact]
private void EnsureCapacity_Double_Doubles()
private void EnsureCapacity_Double_Grows()
{
// Arrange

using var builder = new OperationBuilder();
var currentCapacity = builder.Capacity;
var requested = builder.Capacity * 2;

// Act

builder.EnsureCapacity(currentCapacity * 2);
builder.EnsureCapacity(requested);

// Assert

Assert.Equal(currentCapacity * 2, builder.Capacity);
AssertAtLeast(requested, builder.Capacity);
}

[Fact]
private void EnsureCapacity_OneMoreThanDouble_Quadruples()
private void EnsureCapacity_OneMoreThanDouble_Grows()
{
// Arrange

using var builder = new OperationBuilder();
var currentCapacity = builder.Capacity;
var requested = builder.Capacity * 2 + 1;

// Act

builder.EnsureCapacity(currentCapacity * 2 + 1);
builder.EnsureCapacity(requested);

// Assert

Assert.Equal(currentCapacity * 4, builder.Capacity);
AssertAtLeast(requested, builder.Capacity);
}

[Fact]
private void EnsureCapacity_Quadruple_Quadruples()
private void EnsureCapacity_Quadruple_Grows()
{
// Arrange

using var builder = new OperationBuilder();
var currentCapacity = builder.Capacity;
var requested = builder.Capacity * 4;

// Act

builder.EnsureCapacity(currentCapacity * 4);
builder.EnsureCapacity(requested);

// Assert

Assert.Equal(currentCapacity * 4, builder.Capacity);
AssertAtLeast(requested, builder.Capacity);
}

private static void AssertAtLeast(int requested, int actualCapacity) =>
Assert.True(actualCapacity >= requested,
$"Expected a capacity of at least {requested}, found {actualCapacity}.");

#endregion

#region Helpers
Expand Down
18 changes: 12 additions & 6 deletions tests/Couchbase.UnitTests/Utils/SlicedMemoryOwnerTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Buffers;
using System.Linq;
using Couchbase.UnitTests.Helpers;
using Couchbase.Utils;
Expand All @@ -9,6 +8,13 @@ namespace Couchbase.UnitTests.Utils
{
public class SlicedMemoryOwnerTests
{
// These tests use FakeMemoryOwner rather than MemoryPool<byte>.Shared.Rent, because Rent
// only promises *at least* the requested size. On .NET Framework the pool falls back to a
// larger bucket when the requested one is exhausted, so a Rent(32) under load returns 64
// and every assertion below that depends on the buffer being exactly 32 bytes fails.
private static FakeMemoryOwner<byte> ExactlySized(int length) =>
new FakeMemoryOwner<byte>(new byte[length]);

#region ctor1

[Fact]
Expand All @@ -27,7 +33,7 @@ public void ctor1_NullMemoryOwner_ArgumentNullException()
public void ctor1_StartOutsideRange_ArgumentOutOfRangeException(int start)
{
// Act/Assert
using (var memory = MemoryPool<byte>.Shared.Rent(32))
using (var memory = ExactlySized(32))
{
Assert.Throws<ArgumentOutOfRangeException>(() => new SlicedMemoryOwner<byte>(memory, start));
}
Expand All @@ -40,7 +46,7 @@ public void ctor1_StartOutsideRange_ArgumentOutOfRangeException(int start)
public void ctor1_StartWithinRange_SliceUntilEnd(int start, int expectedLength)
{
// Act/Assert
using (var memory = new SlicedMemoryOwner<byte>(MemoryPool<byte>.Shared.Rent(32), start))
using (var memory = new SlicedMemoryOwner<byte>(ExactlySized(32), start))
{
Assert.Equal(expectedLength, memory.Memory.Length);
}
Expand Down Expand Up @@ -82,7 +88,7 @@ public void ctor2_NullMemoryOwner_ArgumentNullException()
public void ctor2_NegativeStart_ArgumentOutOfRangeException()
{
// Act/Assert
using (var memory = MemoryPool<byte>.Shared.Rent(32))
using (var memory = ExactlySized(32))
{
Assert.Throws<ArgumentOutOfRangeException>(() => new SlicedMemoryOwner<byte>(memory, -1, 10));
}
Expand All @@ -96,7 +102,7 @@ public void ctor2_NegativeStart_ArgumentOutOfRangeException()
public void ctor2_StartOutsideRange_ArgumentOutOfRangeException(int start)
{
// Act/Assert
using (var memory = MemoryPool<byte>.Shared.Rent(32))
using (var memory = ExactlySized(32))
{
Assert.Throws<ArgumentOutOfRangeException>(() => new SlicedMemoryOwner<byte>(memory, start, 1));
}
Expand All @@ -109,7 +115,7 @@ public void ctor2_StartOutsideRange_ArgumentOutOfRangeException(int start)
public void ctor2_StartWithinRange_SliceLength(int start, int length)
{
// Act/Assert
using (var memory = new SlicedMemoryOwner<byte>(MemoryPool<byte>.Shared.Rent(32), start, length))
using (var memory = new SlicedMemoryOwner<byte>(ExactlySized(32), start, length))
{
Assert.Equal(length, memory.Memory.Length);
}
Expand Down
Loading