diff options
Diffstat (limited to 'src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs')
-rw-r--r-- | src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs b/src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs new file mode 100644 index 000000000..18d405613 --- /dev/null +++ b/src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs @@ -0,0 +1,274 @@ +// 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. + +using System; +using Xunit; + +namespace Apache.Arrow.Tests +{ + public class ArrowArrayTests + { + + [Fact] + public void ThrowsWhenGetValueIndexOutOfBounds() + { + var array = new Int64Array.Builder().Append(1).Append(2).Build(); + Assert.Throws<ArgumentOutOfRangeException>(() => array.GetValue(-1)); + Assert.Equal(1, array.GetValue(0)); + Assert.Equal(2, array.GetValue(1)); + Assert.Throws<ArgumentOutOfRangeException>(() => array.GetValue(2)); + } + + [Fact] + public void ThrowsWhenGetValueAndOffsetIndexOutOfBounds() + { + var array = new BinaryArray.Builder().Append(1).Append(2).Build(); + Assert.Throws<ArgumentOutOfRangeException>(() => array.GetValueLength(-1)); + Assert.Equal(1, array.GetValueLength(0)); + Assert.Equal(1, array.GetValueLength(1)); + Assert.Throws<ArgumentOutOfRangeException>(() => array.GetValueLength(2)); + +#pragma warning disable 618 + Assert.Throws<ArgumentOutOfRangeException>(() => array.GetValueOffset(-1)); + Assert.Equal(0, array.GetValueOffset(0)); + Assert.Equal(1, array.GetValueOffset(1)); + Assert.Equal(2, array.GetValueOffset(2)); + Assert.Throws<ArgumentOutOfRangeException>(() => array.GetValueOffset(3)); +#pragma warning restore 618 + + Assert.Throws<IndexOutOfRangeException>(() => array.ValueOffsets[-1]); + Assert.Equal(0, array.ValueOffsets[0]); + Assert.Equal(1, array.ValueOffsets[1]); + Assert.Equal(2, array.ValueOffsets[2]); + Assert.Throws<IndexOutOfRangeException>(() => array.ValueOffsets[3]); + + } + + [Fact] + public void IsValidValue() + { + const int totalValueCount = 8; + const byte nullBitmap = 0b_11110011; + + var nullBitmapBuffer = new ArrowBuffer.Builder<byte>().Append(nullBitmap).Build(); + var valueBuffer = new ArrowBuffer.Builder<long>().Append(0).Append(1).Append(4).Append(5).Append(6).Append(7).Append(8).Build(); + + //Check all offset and length + for (var offset = 0; offset < totalValueCount; offset++) + { + var nullCount = totalValueCount - offset - BitUtility.CountBits(nullBitmapBuffer.Span, offset); + for (var length = 1; length + offset < totalValueCount; length++) + { + TestIsValid(valueBuffer, nullBitmapBuffer, length, nullCount, offset); + } + } + + void TestIsValid(ArrowBuffer valueBuf, ArrowBuffer nullBitmapBuf, int length, int nullCount, int offset) + { + var array = new Int64Array(valueBuf, nullBitmapBuf, length, nullCount, offset); + for (var i = 0; i < length; i++) + { + if (BitUtility.GetBit(nullBitmap, i + offset)) + { + Assert.True(array.IsValid(i)); + } + else + { + Assert.False(array.IsValid(i)); + } + } + } + } + + [Fact] + public void SliceArray() + { + TestSlice<Int32Array, Int32Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<Int8Array, Int8Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<Int16Array, Int16Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<Int64Array, Int64Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<UInt8Array, UInt8Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<UInt16Array, UInt16Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<UInt32Array, UInt32Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<UInt64Array, UInt64Array.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<FloatArray, FloatArray.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<DoubleArray, DoubleArray.Builder>(x => x.Append(10).Append(20).Append(30)); + TestSlice<Date32Array, Date32Array.Builder>(x => x.Append(new DateTime(2019, 1, 1)).Append(new DateTime(2019, 1, 2)).Append(new DateTime(2019, 1, 3))); + TestSlice<Date64Array, Date64Array.Builder>(x => x.Append(new DateTime(2019, 1, 1)).Append(new DateTime(2019, 1, 2)).Append(new DateTime(2019, 1, 3))); + TestSlice<StringArray, StringArray.Builder>(x => x.Append("10").Append("20").Append("30")); + } + + [Fact] + public void SlicePrimitiveArrayWithNulls() + { + TestSlice<Int32Array, Int32Array.Builder>(x => x.Append(10).Append(20).AppendNull().Append(30)); + TestSlice<Int8Array, Int8Array.Builder>(x => x.Append(10).AppendNull().Append(20).AppendNull().Append(30)); + TestSlice<Int16Array, Int16Array.Builder>(x => x.Append(10).Append(20).AppendNull().Append(30)); + TestSlice<Int64Array, Int64Array.Builder>(x => x.Append(10).Append(20).AppendNull().Append(30)); + TestSlice<UInt8Array, UInt8Array.Builder>(x => x.Append(10).Append(20).Append(30).AppendNull()); + TestSlice<UInt16Array, UInt16Array.Builder>(x => x.Append(10).Append(20).AppendNull().AppendNull().Append(30)); + TestSlice<UInt32Array, UInt32Array.Builder>(x => x.Append(10).Append(20).AppendNull().Append(30)); + TestSlice<UInt64Array, UInt64Array.Builder>(x => x.Append(10).Append(20).AppendNull().Append(30)); + TestSlice<FloatArray, FloatArray.Builder>(x => x.AppendNull().Append(10).Append(20).AppendNull().Append(30)); + TestSlice<DoubleArray, DoubleArray.Builder>(x => x.Append(10).Append(20).AppendNull().Append(30)); + TestSlice<Date32Array, Date32Array.Builder>(x => x.Append(new DateTime(2019, 1, 1)).Append(new DateTime(2019, 1, 2)).AppendNull().Append(new DateTime(2019, 1, 3))); + TestSlice<Date64Array, Date64Array.Builder>(x => x.Append(new DateTime(2019, 1, 1)).Append(new DateTime(2019, 1, 2)).AppendNull().Append(new DateTime(2019, 1, 3))); + } + + [Fact] + public void SliceBooleanArray() + { + TestSlice<BooleanArray, BooleanArray.Builder>(x => x.Append(true).Append(false).Append(true)); + TestSlice<BooleanArray, BooleanArray.Builder>(x => x.Append(true).Append(false).AppendNull().Append(true)); + } + + [Fact] + public void SliceStringArrayWithNullsAndEmptyStrings() + { + TestSlice<StringArray, StringArray.Builder>(x => x.Append("10").AppendNull().Append("30")); + TestSlice<StringArray, StringArray.Builder>(x => x.Append("10").Append(string.Empty).Append("30")); + TestSlice<StringArray, StringArray.Builder>(x => x.Append("10").Append(string.Empty).AppendNull().Append("30")); + TestSlice<StringArray, StringArray.Builder>(x => x.Append("10").AppendNull().Append(string.Empty).Append("30")); + TestSlice<StringArray, StringArray.Builder>(x => x.Append("10").AppendNull().Append(string.Empty).AppendNull().Append("30")); + } + + private static void TestSlice<TArray, TArrayBuilder>(Action<TArrayBuilder> action) + where TArray : IArrowArray + where TArrayBuilder : IArrowArrayBuilder<TArray>, new() + { + var builder = new TArrayBuilder(); + action(builder); + var baseArray = builder.Build(default) as Array; + Assert.NotNull(baseArray); + var totalLength = baseArray.Length; + var validator = new ArraySliceValidator(baseArray); + + //Check all offset and length + for (var offset = 0; offset < totalLength; offset++) + { + for (var length = 1; length + offset <= totalLength; length++) + { + var targetArray = baseArray.Slice(offset, length); + targetArray.Accept(validator); + } + } + } + + private class ArraySliceValidator : + IArrowArrayVisitor<Int8Array>, + IArrowArrayVisitor<Int16Array>, + IArrowArrayVisitor<Int32Array>, + IArrowArrayVisitor<Int64Array>, + IArrowArrayVisitor<UInt8Array>, + IArrowArrayVisitor<UInt16Array>, + IArrowArrayVisitor<UInt32Array>, + IArrowArrayVisitor<UInt64Array>, + IArrowArrayVisitor<Date32Array>, + IArrowArrayVisitor<Date64Array>, + IArrowArrayVisitor<FloatArray>, + IArrowArrayVisitor<DoubleArray>, + IArrowArrayVisitor<BooleanArray>, + IArrowArrayVisitor<StringArray> + { + private readonly IArrowArray _baseArray; + + public ArraySliceValidator(IArrowArray baseArray) + { + _baseArray = baseArray; + } + + public void Visit(Int8Array array) => ValidateArrays(array); + public void Visit(Int16Array array) => ValidateArrays(array); + public void Visit(Int32Array array) => ValidateArrays(array); + public void Visit(Int64Array array) => ValidateArrays(array); + public void Visit(UInt8Array array) => ValidateArrays(array); + public void Visit(UInt16Array array) => ValidateArrays(array); + public void Visit(UInt32Array array) => ValidateArrays(array); + public void Visit(UInt64Array array) => ValidateArrays(array); + + public void Visit(Date32Array array) + { + ValidateArrays(array); + Assert.IsAssignableFrom<Date32Array>(_baseArray); + var baseArray = (Date32Array)_baseArray; + + Assert.Equal(baseArray.GetDateTimeOffset(array.Offset), array.GetDateTimeOffset(0)); + } + + public void Visit(Date64Array array) + { + ValidateArrays(array); + Assert.IsAssignableFrom<Date64Array>(_baseArray); + var baseArray = (Date64Array)_baseArray; + + Assert.Equal(baseArray.GetDateTimeOffset(array.Offset), array.GetDateTimeOffset(0)); + } + + public void Visit(FloatArray array) => ValidateArrays(array); + public void Visit(DoubleArray array) => ValidateArrays(array); + public void Visit(StringArray array) => ValidateArrays(array); + public void Visit(BooleanArray array) => ValidateArrays(array); + + public void Visit(IArrowArray array) => throw new NotImplementedException(); + + private void ValidateArrays<T>(PrimitiveArray<T> slicedArray) + where T : struct, IEquatable<T> + { + Assert.IsAssignableFrom<PrimitiveArray<T>>(_baseArray); + var baseArray = (PrimitiveArray<T>)_baseArray; + + Assert.True(baseArray.NullBitmapBuffer.Span.SequenceEqual(slicedArray.NullBitmapBuffer.Span)); + Assert.True( + baseArray.ValueBuffer.Span.CastTo<T>().Slice(slicedArray.Offset, slicedArray.Length) + .SequenceEqual(slicedArray.Values)); + + Assert.Equal(baseArray.GetValue(slicedArray.Offset), slicedArray.GetValue(0)); + } + + private void ValidateArrays(BooleanArray slicedArray) + { + Assert.IsAssignableFrom<BooleanArray>(_baseArray); + var baseArray = (BooleanArray)_baseArray; + + Assert.True(baseArray.NullBitmapBuffer.Span.SequenceEqual(slicedArray.NullBitmapBuffer.Span)); + Assert.True(baseArray.Values.SequenceEqual(slicedArray.Values)); + + Assert.True( + baseArray.ValueBuffer.Span.Slice(0, (int) Math.Ceiling(slicedArray.Length / 8.0)) + .SequenceEqual(slicedArray.Values)); + + Assert.Equal(baseArray.GetValue(slicedArray.Offset), slicedArray.GetValue(0)); + +#pragma warning disable CS0618 + Assert.Equal(baseArray.GetBoolean(slicedArray.Offset), slicedArray.GetBoolean(0)); +#pragma warning restore CS0618 + } + + private void ValidateArrays(BinaryArray slicedArray) + { + Assert.IsAssignableFrom<BinaryArray>(_baseArray); + var baseArray = (BinaryArray)_baseArray; + + Assert.True(baseArray.Values.SequenceEqual(slicedArray.Values)); + Assert.True(baseArray.NullBitmapBuffer.Span.SequenceEqual(slicedArray.NullBitmapBuffer.Span)); + Assert.True( + baseArray.ValueOffsetsBuffer.Span.CastTo<int>().Slice(slicedArray.Offset, slicedArray.Length + 1) + .SequenceEqual(slicedArray.ValueOffsets)); + + Assert.True(baseArray.GetBytes(slicedArray.Offset).SequenceEqual(slicedArray.GetBytes(0))); + } + } + } +} |