diff --git a/tests/Couchbase.UnitTests/Core/IO/Operations/OperationBuilderTests.cs b/tests/Couchbase.UnitTests/Core/IO/Operations/OperationBuilderTests.cs index 0cbb5c470..c1892b141 100644 --- a/tests/Couchbase.UnitTests/Core/IO/Operations/OperationBuilderTests.cs +++ b/tests/Couchbase.UnitTests/Core/IO/Operations/OperationBuilderTests.cs @@ -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 diff --git a/tests/Couchbase.UnitTests/Utils/SlicedMemoryOwnerTests.cs b/tests/Couchbase.UnitTests/Utils/SlicedMemoryOwnerTests.cs index a0e7818f1..33fd138ac 100644 --- a/tests/Couchbase.UnitTests/Utils/SlicedMemoryOwnerTests.cs +++ b/tests/Couchbase.UnitTests/Utils/SlicedMemoryOwnerTests.cs @@ -1,5 +1,4 @@ using System; -using System.Buffers; using System.Linq; using Couchbase.UnitTests.Helpers; using Couchbase.Utils; @@ -9,6 +8,13 @@ namespace Couchbase.UnitTests.Utils { public class SlicedMemoryOwnerTests { + // These tests use FakeMemoryOwner rather than MemoryPool.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 ExactlySized(int length) => + new FakeMemoryOwner(new byte[length]); + #region ctor1 [Fact] @@ -27,7 +33,7 @@ public void ctor1_NullMemoryOwner_ArgumentNullException() public void ctor1_StartOutsideRange_ArgumentOutOfRangeException(int start) { // Act/Assert - using (var memory = MemoryPool.Shared.Rent(32)) + using (var memory = ExactlySized(32)) { Assert.Throws(() => new SlicedMemoryOwner(memory, start)); } @@ -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(MemoryPool.Shared.Rent(32), start)) + using (var memory = new SlicedMemoryOwner(ExactlySized(32), start)) { Assert.Equal(expectedLength, memory.Memory.Length); } @@ -82,7 +88,7 @@ public void ctor2_NullMemoryOwner_ArgumentNullException() public void ctor2_NegativeStart_ArgumentOutOfRangeException() { // Act/Assert - using (var memory = MemoryPool.Shared.Rent(32)) + using (var memory = ExactlySized(32)) { Assert.Throws(() => new SlicedMemoryOwner(memory, -1, 10)); } @@ -96,7 +102,7 @@ public void ctor2_NegativeStart_ArgumentOutOfRangeException() public void ctor2_StartOutsideRange_ArgumentOutOfRangeException(int start) { // Act/Assert - using (var memory = MemoryPool.Shared.Rent(32)) + using (var memory = ExactlySized(32)) { Assert.Throws(() => new SlicedMemoryOwner(memory, start, 1)); } @@ -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(MemoryPool.Shared.Rent(32), start, length)) + using (var memory = new SlicedMemoryOwner(ExactlySized(32), start, length)) { Assert.Equal(length, memory.Memory.Length); }