summaryrefslogtreecommitdiffstats
path: root/src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs')
-rw-r--r--src/arrow/csharp/test/Apache.Arrow.Tests/ArrowArrayTests.cs274
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)));
+ }
+ }
+ }
+}