blob: 148ccea0b271312f5c0a171f19c90654e20ca2d7 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace Apache.Arrow.Tests
{
using System;
using System.Linq;
using Xunit;
/// <summary>
/// The <see cref="ArrowBufferBitmapBuilderTests"/> class provides unit tests for the
/// <see cref="ArrowBuffer.BitmapBuilder"/> class.
/// </summary>
public class ArrowBufferBitmapBuilderTests
{
public class Append
{
[Theory]
[InlineData(new bool[] { }, false, 1, 0, 1)]
[InlineData(new bool[] { }, true, 1, 1, 0)]
[InlineData(new[] { true, false }, true, 3, 2, 1)]
[InlineData(new[] { true, false }, false, 3, 1, 2)]
public void IncreasesLength(
bool[] initialContents,
bool valueToAppend,
int expectedLength,
int expectedSetBitCount,
int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(initialContents);
// Act
var actualReturnValue = builder.Append(valueToAppend);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedLength, builder.Length);
Assert.True(builder.Capacity >= expectedLength);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
}
[Theory]
[InlineData(new bool[] { }, false)]
[InlineData(new bool[] { }, true)]
[InlineData(new[] { true, false }, true)]
[InlineData(new[] { true, false }, false)]
public void AfterClearIncreasesLength(bool[] initialContentsToClear, bool valueToAppend)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(initialContentsToClear);
builder.Clear();
// Act
var actualReturnValue = builder.Append(valueToAppend);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(1, builder.Length);
Assert.True(builder.Capacity >= 1);
Assert.Equal(valueToAppend ? 1 : 0, builder.SetBitCount);
Assert.Equal(valueToAppend ? 0 : 1, builder.UnsetBitCount);
}
[Fact]
public void IncreasesCapacityWhenRequired()
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
int initialCapacity = builder.Capacity;
builder.AppendRange(true, initialCapacity); // Fill to capacity.
// Act
var actualReturnValue = builder.Append(true);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(initialCapacity + 1, builder.Length);
Assert.True(builder.Capacity >= initialCapacity + 1);
}
}
public class AppendSpan
{
[Theory]
[InlineData(new byte[] { 0b00000110 }, 4, 4, 2, 2)]
[InlineData(new byte[] { 0b11111110 }, 4, 4, 3, 1)]
[InlineData(new byte[] { 0b11111110, 0b00000001 }, 9, 9, 8, 1)]
[InlineData(new byte[] { 0b11111001, 0b00000001 }, 9, 9, 7, 2)]
public void BitsAreAppendedToEmptyBuilder(byte[] bytesToAppend,
int validBits,
int expectedLength,
int expectedSetBitCount,
int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
// Act
var actualReturnValue = builder.Append(new Span<byte>(bytesToAppend), validBits);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedLength, builder.Length);
Assert.True(builder.Capacity >= expectedLength);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
}
[Theory]
[InlineData(new byte[] { 6 }, 4, 12, 10, 2)]
[InlineData(new byte[] { 254 }, 4, 12, 11, 1)]
[InlineData(new byte[] { 254, 1 }, 9, 17, 16, 1)]
[InlineData(new byte[] { 249, 1 }, 9, 17, 15, 2)]
public void BitsAreAppendedToBuilderContainingByteAlignedData(byte[] bytesToAppend,
int validBits,
int expectedLength,
int expectedSetBitCount,
int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(true, 8);
// Act
var actualReturnValue = builder.Append(new Span<byte>(bytesToAppend), validBits);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedLength, builder.Length);
Assert.True(builder.Capacity >= expectedLength);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
}
[Theory]
[InlineData(new byte[] { 6 }, 4, 13, 11, 2)]
[InlineData(new byte[] { 254 }, 4, 13, 12, 1)]
[InlineData(new byte[] { 254, 1 }, 9, 18, 17, 1)]
[InlineData(new byte[] { 249, 1 }, 9, 18, 16, 2)]
public void BitsAreAppendedToBuilderContainingNotAlignedData(byte[] bytesToAppend,
int validBits,
int expectedLength,
int expectedSetBitCount,
int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(true, 9);
// Act
var actualReturnValue = builder.Append(new Span<byte>(bytesToAppend), validBits);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedLength, builder.Length);
Assert.True(builder.Capacity >= expectedLength);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
}
[Fact]
public void EmptySpanAppendsCorrectNumberOfBits()
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(true, 8);
// Act
var actualReturnValue = builder.Append(Span<byte>.Empty, 8);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(16, builder.Length);
Assert.True(builder.Capacity >= 16);
Assert.Equal(16, builder.SetBitCount);
Assert.Equal(0, builder.UnsetBitCount);
}
[Fact]
public void ThrowsWhenLengthIsTooBig()
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(true, 8);
// Act
Assert.Throws<ArgumentException>(() => builder.Append(new byte[] { 0b0010111 }, 9));
Assert.Throws<ArgumentException>(() => builder.Append(new byte[] { 0, 1, 3, 4 }, 33));
}
}
public class AppendRange
{
[Theory]
[InlineData(new bool[] { }, new bool[] { }, 0, 0, 0)]
[InlineData(new bool[] { }, new[] { true, false }, 2, 1, 1)]
[InlineData(new[] { true, false }, new bool[] { }, 2, 1, 1)]
[InlineData(new[] { true, false }, new[] { true, false }, 4, 2, 2)]
public void AppendingEnumerableIncreasesLength(
bool[] initialContents,
bool[] toAppend,
int expectedLength,
int expectedSetBitCount,
int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(initialContents);
// Act
var actualReturnValue = builder.AppendRange(toAppend);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedLength, builder.Length);
Assert.True(builder.Capacity >= expectedLength);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
}
[Theory]
[InlineData(new bool[] { }, true, 0, 0, 0, 0)]
[InlineData(new bool[] { }, true, 2, 2, 2, 0)]
[InlineData(new[] { true, false }, false, 0, 2, 1, 1)]
[InlineData(new[] { true, false }, false, 2, 4, 1, 3)]
[InlineData(new[] { true, false }, true, 2, 4, 3, 1)]
public void AppendingValueMultipleTimesIncreasesLength(
bool[] initialContents,
bool valueToAppend,
int numberOfTimes,
int expectedLength,
int expectedSetBitCount,
int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(initialContents);
// Act
var actualReturnValue = builder.AppendRange(valueToAppend, numberOfTimes);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedLength, builder.Length);
Assert.True(builder.Capacity >= expectedLength);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
}
}
public class Build
{
[Theory]
[InlineData(new bool[] { }, new byte[] { })]
[InlineData(new[] { true, false, true, false }, new byte[] { 0b00000101 })]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false, true, false },
new byte[] { 0b01010101, 0b00000101 })]
public void AppendedRangeBitPacks(bool[] contents, byte[] expectedBytes)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(contents);
// Act
var buf = builder.Build();
// Assert
AssertBuffer(expectedBytes, buf);
}
}
public class Clear
{
[Theory]
[InlineData(10)]
[InlineData(100)]
public void ClearingSetsBitCountToZero(int numBitsBeforeClear)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
var data = Enumerable.Repeat(true, numBitsBeforeClear).Select(x => x).ToArray();
builder.AppendRange(data);
// Act
var actualReturnValue = builder.Clear();
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(0, builder.Length);
}
}
public class Resize
{
[Theory]
[InlineData(new bool[] { }, 256, 0, 256)]
[InlineData(new[] { true, true, true, true }, 256, 4, 252)]
[InlineData(new[] { false, false, false, false }, 256, 0, 256)]
[InlineData(new[] { true, true, true, true }, 2, 2, 0)]
[InlineData(new[] { true, true, true, true }, 0, 0, 0)]
public void LengthHasExpectedValueAfterResize(
bool[] bits, int newSize, int expectedSetBitCount, int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(bits);
// Act
var actualReturnValue = builder.Resize(newSize);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.True(builder.Capacity >= newSize);
Assert.Equal(newSize, builder.Length);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
}
[Fact]
public void NegativeLengthThrows()
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.Append(false);
builder.Append(true);
// Act/Assert
Assert.Throws<ArgumentOutOfRangeException>(() => builder.Resize(-1));
}
}
public class Reserve
{
[Theory]
[InlineData(0, 0, 0)]
[InlineData(0, 0, 8)]
[InlineData(8, 8, 8)]
[InlineData(8, 8, 16)]
public void CapacityIncreased(int initialCapacity, int numBitsToAppend, int additionalCapacity)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder(initialCapacity);
builder.AppendRange(true, numBitsToAppend);
// Act
var actualReturnValue = builder.Reserve(additionalCapacity);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.True(builder.Capacity >= numBitsToAppend + additionalCapacity);
}
[Fact]
public void NegativeCapacityThrows()
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
// Act/Assert
Assert.Throws<ArgumentOutOfRangeException>(() => builder.Reserve(-1));
}
}
public class Set
{
[Theory]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
2,
new byte[] { 0b01010101, 0b00000001 },
5, 5)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
3,
new byte[] { 0b01011101, 0b00000001 },
6, 4)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
8,
new byte[] { 0b01010101, 0b00000001 },
5, 5)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
9,
new byte[] { 0b01010101, 0b00000011 },
6, 4)]
public void OverloadWithNoValueParameterSetsAsExpected(
bool[] bits, int indexToSet, byte[] expectedBytes,
int expectedSetBitCount, int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(bits);
// Act
var actualReturnValue = builder.Set(indexToSet);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
var buf = builder.Build();
AssertBuffer(expectedBytes, buf);
}
[Theory]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
2, true,
new byte[] { 0b01010101, 0b00000001 },
5, 5)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
2, false,
new byte[] { 0b01010001, 0b00000001 },
4, 6)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
3, true,
new byte[] { 0b01011101, 0b00000001 },
6, 4)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
3, false,
new byte[] { 0b01010101, 0b00000001 },
5, 5)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
8, true,
new byte[] { 0b01010101, 0b00000001 },
5, 5)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
8, false,
new byte[] { 0b01010101, 0b00000000 },
4, 6)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
9, true,
new byte[] { 0b01010101, 0b00000011 },
6, 4)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
9, false,
new byte[] { 0b01010101, 0b00000001 },
5, 5)]
public void OverloadWithValueParameterSetsAsExpected(
bool[] bits, int indexToSet, bool valueToSet, byte[] expectedBytes,
int expectedSetBitCount, int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(bits);
// Act
var actualReturnValue = builder.Set(indexToSet, valueToSet);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
var buf = builder.Build();
AssertBuffer(expectedBytes, buf);
}
[Theory]
[InlineData(0, -1)]
[InlineData(0, 0)]
[InlineData(1, 1)]
[InlineData(10, 10)]
[InlineData(10, 11)]
public void BadIndexThrows(int numBitsToAppend, int indexToSet)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
var bits = Enumerable.Repeat(true, numBitsToAppend);
builder.AppendRange(bits);
// Act/Assert
Assert.Throws<ArgumentOutOfRangeException>(() => builder.Set(indexToSet));
Assert.Throws<ArgumentOutOfRangeException>(() => builder.Set(indexToSet, true));
}
}
public class Swap
{
[Theory]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
0, 2,
new byte[] { 0b01010101, 0b00000001 })]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
0, 3,
new byte[] { 0b01011100, 0b00000001 })]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
4, 8,
new byte[] { 0b01010101, 0b00000001 })]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
4, 9,
new byte[] { 0b01000101, 0b00000011 })]
public void SwapsAsExpected(bool[] bits, int firstIndex, int secondIndex, byte[] expectedBytes)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(bits);
// Act
var actualReturnValue = builder.Swap(firstIndex, secondIndex);
// Assert
Assert.Equal(builder, actualReturnValue);
var buf = builder.Build();
AssertBuffer(expectedBytes, buf);
}
[Theory]
[InlineData(0, -1, 0)]
[InlineData(0, 0, -1)]
[InlineData(0, 0, 0)]
[InlineData(1, 0, 1)]
[InlineData(1, 1, 0)]
[InlineData(1, 0, -1)]
[InlineData(1, -1, 0)]
[InlineData(1, 1, 1)]
[InlineData(10, 10, 0)]
[InlineData(10, 0, 10)]
[InlineData(10, 10, 10)]
[InlineData(10, 11, 0)]
[InlineData(10, 0, 11)]
[InlineData(10, 11, 11)]
public void BadIndicesThrows(int numBitsToAppend, int firstIndex, int secondIndex)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
var bits = Enumerable.Repeat(true, numBitsToAppend);
builder.AppendRange(bits);
// Act/Assert
Assert.Throws<ArgumentOutOfRangeException>(() => builder.Swap(firstIndex, secondIndex));
}
}
public class Toggle
{
[Theory]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
2,
new byte[] { 0b01010001, 0b00000001 },
4, 6)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
3,
new byte[] { 0b01011101, 0b00000001 },
6, 4)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
8,
new byte[] { 0b01010101, 0b00000000 },
4, 6)]
[InlineData(
new[] { true, false, true, false, true, false, true, false, true, false },
9,
new byte[] { 0b01010101, 0b00000011 },
6, 4)]
public void TogglesAsExpected(
bool[] bits, int indexToToggle, byte[] expectedBytes,
int expectedSetBitCount, int expectedUnsetBitCount)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
builder.AppendRange(bits);
// Act
var actualReturnValue = builder.Toggle(indexToToggle);
// Assert
Assert.Equal(builder, actualReturnValue);
Assert.Equal(expectedSetBitCount, builder.SetBitCount);
Assert.Equal(expectedUnsetBitCount, builder.UnsetBitCount);
var buf = builder.Build();
AssertBuffer(expectedBytes, buf);
}
[Theory]
[InlineData(0, -1)]
[InlineData(0, 0)]
[InlineData(1, 1)]
[InlineData(10, 10)]
[InlineData(10, 11)]
public void BadIndexThrows(int numBitsToAppend, int indexToToggle)
{
// Arrange
var builder = new ArrowBuffer.BitmapBuilder();
var bits = Enumerable.Repeat(true, numBitsToAppend);
builder.AppendRange(bits);
// Act/Assert
Assert.Throws<ArgumentOutOfRangeException>(() => builder.Toggle(indexToToggle));
}
}
private static void AssertBuffer(byte[] expectedBytes, ArrowBuffer buf)
{
Assert.True(buf.Length >= expectedBytes.Length);
for (int i = 0; i < expectedBytes.Length; i++)
{
Assert.Equal(expectedBytes[i], buf.Span[i]);
}
}
}
}