blob: 53116c05803b294bf8111291256234da6dbe194b [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.
#include <gtest/gtest.h>
#include <cmath>
#include <arrow/array.h>
#include <arrow/array/builder_binary.h>
#include <arrow/array/builder_decimal.h>
#include <arrow/array/builder_nested.h>
#include <arrow/array/builder_primitive.h>
#include <arrow/array/builder_time.h>
#include <arrow/array/builder_union.h>
#include <arrow/c/bridge.h>
#include <arrow/compare.h>
#include <arrow/util/decimal.h>
#include "nanoarrow/nanoarrow.h"
using namespace arrow;
// Lightweight versions of ArrowTesting's ARROW_EXPECT_OK. This
// version accomplishes the task of making sure the status message
// ends up in the ctests log.
void ARROW_EXPECT_OK(Status status) {
if (!status.ok()) {
throw std::runtime_error(status.message());
}
}
void ARROW_EXPECT_OK(Result<std::shared_ptr<Array>> result) {
if (!result.ok()) {
throw std::runtime_error(result.status().message());
}
}
TEST(ArrayTest, ArrayTestInit) {
struct ArrowArray array;
EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UNINITIALIZED), NANOARROW_OK);
EXPECT_EQ(array.n_buffers, 0);
ArrowArrayRelease(&array);
EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
EXPECT_EQ(array.n_buffers, 1);
ArrowArrayRelease(&array);
EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
EXPECT_EQ(array.n_buffers, 2);
ArrowArrayRelease(&array);
EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
EXPECT_EQ(array.n_buffers, 3);
ArrowArrayRelease(&array);
EXPECT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DATE64), EINVAL);
}
TEST(ArrayTest, ArrayTestAllocateChildren) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAllocateChildren(&array, 0), NANOARROW_OK);
EXPECT_EQ(array.n_children, 0);
ArrowArrayRelease(&array);
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAllocateChildren(
&array, std::numeric_limits<int64_t>::max() / sizeof(void*)),
ENOMEM);
ArrowArrayRelease(&array);
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAllocateChildren(&array, 2), NANOARROW_OK);
EXPECT_EQ(array.n_children, 2);
ASSERT_NE(array.children, nullptr);
ASSERT_NE(array.children[0], nullptr);
ASSERT_NE(array.children[1], nullptr);
ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromType(array.children[1], NANOARROW_TYPE_STRING),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayAllocateChildren(&array, 0), EINVAL);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestAllocateDictionary) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAllocateDictionary(&array), NANOARROW_OK);
ASSERT_NE(array.dictionary, nullptr);
ASSERT_EQ(ArrowArrayInitFromType(array.dictionary, NANOARROW_TYPE_STRING),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayAllocateDictionary(&array), EINVAL);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestInitFromSchema) {
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowError error;
ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 2), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaInitFromType(schema.children[1], NANOARROW_TYPE_STRING),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayInitFromSchema(&array, &schema, &error), NANOARROW_OK);
EXPECT_EQ(array.n_children, 2);
EXPECT_EQ(array.children[0]->n_buffers, 2);
EXPECT_EQ(array.children[1]->n_buffers, 3);
ArrowArrayRelease(&array);
ArrowSchemaRelease(&schema);
}
TEST(ArrayTest, ArrayTestSetBitmap) {
struct ArrowBitmap bitmap;
ArrowBitmapInit(&bitmap);
ASSERT_EQ(ArrowBitmapAppend(&bitmap, true, 9), NANOARROW_OK);
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
ArrowArraySetValidityBitmap(&array, &bitmap);
EXPECT_EQ(bitmap.buffer.data, nullptr);
const uint8_t* bitmap_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
EXPECT_EQ(bitmap_buffer[0], 0xff);
EXPECT_EQ(bitmap_buffer[1], 0x01);
EXPECT_EQ(ArrowArrayValidityBitmap(&array)->buffer.data, array.buffers[0]);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestSetBuffer) {
// the array ["a", null, "bc", null, "def", null, "ghij"]
uint8_t validity_bitmap[] = {0x55};
int32_t offsets[] = {0, 1, 1, 3, 3, 6, 6, 10, 10};
const char* data = "abcdefghij";
struct ArrowBuffer buffer0, buffer1, buffer2;
ArrowBufferInit(&buffer0);
ASSERT_EQ(ArrowBufferAppend(&buffer0, validity_bitmap, 1), NANOARROW_OK);
ArrowBufferInit(&buffer1);
ASSERT_EQ(ArrowBufferAppend(&buffer1, offsets, 9 * sizeof(int32_t)), NANOARROW_OK);
ArrowBufferInit(&buffer2);
ASSERT_EQ(ArrowBufferAppend(&buffer2, data, strlen(data)), NANOARROW_OK);
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
EXPECT_EQ(ArrowArraySetBuffer(&array, 0, &buffer0), NANOARROW_OK);
EXPECT_EQ(ArrowArraySetBuffer(&array, 1, &buffer1), NANOARROW_OK);
EXPECT_EQ(ArrowArraySetBuffer(&array, 2, &buffer2), NANOARROW_OK);
EXPECT_EQ(memcmp(array.buffers[0], validity_bitmap, 1), 0);
EXPECT_EQ(memcmp(array.buffers[1], offsets, 8 * sizeof(int32_t)), 0);
EXPECT_EQ(memcmp(array.buffers[2], data, 10), 0);
EXPECT_EQ(ArrowArrayBuffer(&array, 0)->data, array.buffers[0]);
EXPECT_EQ(ArrowArrayBuffer(&array, 1)->data, array.buffers[1]);
EXPECT_EQ(ArrowArrayBuffer(&array, 2)->data, array.buffers[2]);
// try to set a buffer that isn't, 0, 1, or 2
EXPECT_EQ(ArrowArraySetBuffer(&array, 3, &buffer0), EINVAL);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestBuildByBuffer) {
// the array ["a", null, "bc", null, "def", null, "ghij"]
uint8_t validity_bitmap[] = {0x55};
int8_t validity_array[] = {1, 0, 1, 0, 1, 0, 1};
int32_t offsets[] = {0, 1, 1, 3, 3, 6, 6, 10, 10};
const char* data = "abcdefghij";
struct ArrowArray array;
struct ArrowError error;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowBitmapReserve(ArrowArrayValidityBitmap(&array), 100), NANOARROW_OK);
ArrowBitmapAppendInt8Unsafe(ArrowArrayValidityBitmap(&array), validity_array, 7);
ASSERT_EQ(ArrowBufferReserve(ArrowArrayBuffer(&array, 1), 100), NANOARROW_OK);
ArrowBufferAppendUnsafe(ArrowArrayBuffer(&array, 1), offsets, 8 * sizeof(int32_t));
ASSERT_EQ(ArrowBufferReserve(ArrowArrayBuffer(&array, 2), 100), NANOARROW_OK);
ArrowBufferAppendUnsafe(ArrowArrayBuffer(&array, 2), data, 10);
array.length = 7;
EXPECT_EQ(ArrowArrayShrinkToFit(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
EXPECT_EQ(memcmp(array.buffers[0], validity_bitmap, 1), 0);
EXPECT_EQ(memcmp(array.buffers[1], offsets, 8 * sizeof(int32_t)), 0);
EXPECT_EQ(memcmp(array.buffers[2], data, 10), 0);
EXPECT_EQ(ArrowArrayBuffer(&array, 0)->data, array.buffers[0]);
EXPECT_EQ(ArrowArrayBuffer(&array, 1)->data, array.buffers[1]);
EXPECT_EQ(ArrowArrayBuffer(&array, 2)->data, array.buffers[2]);
EXPECT_EQ(ArrowArrayBuffer(&array, 0)->size_bytes, 1);
EXPECT_EQ(ArrowArrayBuffer(&array, 1)->size_bytes, 8 * sizeof(int32_t));
EXPECT_EQ(ArrowArrayBuffer(&array, 2)->size_bytes, 10);
array.length = 8;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(ArrowErrorMessage(&error),
"Expected string array buffer 1 to have size >= 36 bytes but found buffer "
"with 32 bytes");
array.length = 7;
int32_t* offsets_buffer = reinterpret_cast<int32_t*>(ArrowArrayBuffer(&array, 1)->data);
offsets_buffer[7] = offsets_buffer[7] + 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(ArrowErrorMessage(&error),
"Expected string array buffer 2 to have size >= 11 bytes but found buffer "
"with 10 bytes");
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestExplicitValidationLevel) {
struct ArrowArray array;
struct ArrowError error;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("1234")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("5678")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, &error),
NANOARROW_OK);
int32_t* offsets =
const_cast<int32_t*>(reinterpret_cast<const int32_t*>(array.buffers[1]));
// Valid at validation_level < NANOARROW_VALIDATION_LEVEL_FULL
offsets[1] = -1;
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, &error),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_MINIMAL, &error),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_DEFAULT, &error),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "[1] Expected element size >= 0");
offsets[1] = 4;
// Valid at validation_level < NANOARROW_VALIDATION_LEVEL_DEFAULT
offsets[0] = -1;
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, &error),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_MINIMAL, &error),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_DEFAULT, &error),
EINVAL);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "Expected first offset >= 0 but found -1");
offsets[0] = 0;
// Valid at validation_level < NANOARROW_VALIDATION_LEVEL_MINIMAL
ArrowBufferReset(ArrowArrayBuffer(&array, 1));
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_NONE, &error),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_MINIMAL, &error),
EINVAL);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_DEFAULT, &error),
EINVAL);
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message,
"Expected string array buffer 1 to have size >= 12 bytes but found buffer "
"with 0 bytes");
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestValidateMinimalBufferAccess) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("1234")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("5678")), NANOARROW_OK);
// Temporarily make it so that referencing the offsets buffer will crash
// but make sure it has the correct size_bytes and passes minimal validation
uint8_t* tmp = ArrowArrayBuffer(&array, 1)->data;
ArrowArrayBuffer(&array, 1)->data = nullptr;
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_MINIMAL, nullptr),
NANOARROW_OK);
// ...and fails without crashing with the incorrect size_bytes
ArrowArrayBuffer(&array, 1)->size_bytes = 0;
EXPECT_EQ(ArrowArrayFinishBuilding(&array, NANOARROW_VALIDATION_LEVEL_MINIMAL, nullptr),
EINVAL);
// ...restore the pointer so we don't leak memory
ArrowArrayBuffer(&array, 1)->data = tmp;
ArrowArrayRelease(&array);
}
class UnparameterizedTypeTestFixture : public ::testing::TestWithParam<enum ArrowType> {
protected:
enum ArrowType data_type;
};
TEST_P(UnparameterizedTypeTestFixture, ArrayTestBuildEmptyArray) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, GetParam()), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.offset, 0);
EXPECT_EQ(array.length, 0);
EXPECT_EQ(array.null_count, 0);
// For all of these, the validity buffer is the first buffer and should be NULL;
// however, other buffers should not be NULL.
for (int64_t i = 1; i < array.n_buffers; i++) {
if (i == 0) {
EXPECT_EQ(array.buffers[i], nullptr);
} else {
EXPECT_NE(array.buffers[i], nullptr);
}
}
ArrowArrayRelease(&array);
}
// We don't need to exhaustively check here...just a few different categories
// of inputs to ensure our buffer finalizing worked.
INSTANTIATE_TEST_SUITE_P(NanoarrowIpcTest, UnparameterizedTypeTestFixture,
::testing::Values(NANOARROW_TYPE_NA, NANOARROW_TYPE_INT32,
NANOARROW_TYPE_BINARY, NANOARROW_TYPE_STRUCT));
TEST(ArrayTest, ArrayTestAppendToNullArray) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_NA), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 0), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 3);
EXPECT_EQ(array.null_count, 3);
auto arrow_array = ImportArray(&array, null());
ARROW_EXPECT_OK(arrow_array);
auto expected_array = MakeArrayOfNull(null(), 3);
ARROW_EXPECT_OK(expected_array);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_NA), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 0), EINVAL);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 0), EINVAL);
EXPECT_EQ(ArrowArrayAppendDouble(&array, 0), EINVAL);
struct ArrowBufferView buffer_view;
buffer_view.data.data = nullptr;
buffer_view.size_bytes = 0;
EXPECT_EQ(ArrowArrayAppendBytes(&array, buffer_view), EINVAL);
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("")), EINVAL);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestAppendToInt64Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT64), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 3), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, std::numeric_limits<uint64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 5);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const int64_t*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0b00011001);
EXPECT_EQ(data_buffer[0], 1);
EXPECT_EQ(data_buffer[1], 0);
EXPECT_EQ(data_buffer[2], 0);
EXPECT_EQ(data_buffer[3], 3);
EXPECT_EQ(data_buffer[4], 0);
auto arrow_array = ImportArray(&array, int64());
ARROW_EXPECT_OK(arrow_array);
auto builder = Int64Builder();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(3));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToInt32Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayAppendUInt(&array, std::numeric_limits<uint64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 1);
EXPECT_EQ(array.null_count, 0);
auto data_buffer = reinterpret_cast<const int32_t*>(array.buffers[1]);
EXPECT_EQ(array.buffers[0], nullptr);
EXPECT_EQ(data_buffer[0], 123);
auto arrow_array = ImportArray(&array, int32());
ARROW_EXPECT_OK(arrow_array);
auto builder = Int32Builder();
ARROW_EXPECT_OK(builder.Append(123));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToInt16Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT16), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayAppendUInt(&array, std::numeric_limits<uint64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 1);
EXPECT_EQ(array.null_count, 0);
auto data_buffer = reinterpret_cast<const int16_t*>(array.buffers[1]);
EXPECT_EQ(array.buffers[0], nullptr);
EXPECT_EQ(data_buffer[0], 123);
auto arrow_array = ImportArray(&array, int16());
ARROW_EXPECT_OK(arrow_array);
auto builder = Int16Builder();
ARROW_EXPECT_OK(builder.Append(123));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToInt8Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT8), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, std::numeric_limits<int64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayAppendUInt(&array, std::numeric_limits<uint64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 1);
EXPECT_EQ(array.null_count, 0);
auto data_buffer = reinterpret_cast<const int8_t*>(array.buffers[1]);
EXPECT_EQ(array.buffers[0], nullptr);
EXPECT_EQ(data_buffer[0], 123);
auto arrow_array = ImportArray(&array, int8());
ARROW_EXPECT_OK(arrow_array);
auto builder = Int8Builder();
ARROW_EXPECT_OK(builder.Append(123));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToStringArray) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(&array, 1)->capacity_bytes, (5 + 1) * sizeof(int32_t));
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("1234")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("56789")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 5);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto offset_buffer = reinterpret_cast<const int32_t*>(array.buffers[1]);
auto data_buffer = reinterpret_cast<const char*>(array.buffers[2]);
EXPECT_EQ(validity_buffer[0], 0b00011001);
EXPECT_EQ(offset_buffer[0], 0);
EXPECT_EQ(offset_buffer[1], 4);
EXPECT_EQ(offset_buffer[2], 4);
EXPECT_EQ(offset_buffer[3], 4);
EXPECT_EQ(offset_buffer[4], 9);
EXPECT_EQ(memcmp(data_buffer, "123456789", 9), 0);
auto arrow_array = ImportArray(&array, utf8());
ARROW_EXPECT_OK(arrow_array);
auto builder = StringBuilder();
ARROW_EXPECT_OK(builder.Append("1234"));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append("56789"));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendEmptyToString) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(&array, ArrowCharView("")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_NE(array.buffers[2], nullptr);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestAppendToUInt64Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT64), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 4);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const uint64_t*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0x01 | 0x08);
EXPECT_EQ(data_buffer[0], 1);
EXPECT_EQ(data_buffer[1], 0);
EXPECT_EQ(data_buffer[2], 0);
EXPECT_EQ(data_buffer[3], 3);
auto arrow_array = ImportArray(&array, uint64());
ARROW_EXPECT_OK(arrow_array);
auto builder = UInt64Builder();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(3));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToUInt32Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT32), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, std::numeric_limits<uint64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayAppendInt(&array, -1), EINVAL);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 2);
EXPECT_EQ(array.null_count, 0);
auto data_buffer = reinterpret_cast<const uint32_t*>(array.buffers[1]);
EXPECT_EQ(array.buffers[0], nullptr);
EXPECT_EQ(data_buffer[0], 1);
EXPECT_EQ(data_buffer[1], 3);
auto arrow_array = ImportArray(&array, uint32());
ARROW_EXPECT_OK(arrow_array);
auto builder = UInt32Builder();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.Append(3));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToUInt16Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT16), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, std::numeric_limits<uint64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayAppendInt(&array, -1), EINVAL);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 2);
EXPECT_EQ(array.null_count, 0);
auto data_buffer = reinterpret_cast<const uint16_t*>(array.buffers[1]);
EXPECT_EQ(array.buffers[0], nullptr);
EXPECT_EQ(data_buffer[0], 1);
EXPECT_EQ(data_buffer[1], 3);
auto arrow_array = ImportArray(&array, uint16());
ARROW_EXPECT_OK(arrow_array);
auto builder = UInt16Builder();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.Append(3));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToUInt8Array) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_UINT8), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 3), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, std::numeric_limits<uint64_t>::max()), EINVAL);
EXPECT_EQ(ArrowArrayAppendInt(&array, -1), EINVAL);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 2);
EXPECT_EQ(array.null_count, 0);
auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
EXPECT_EQ(array.buffers[0], nullptr);
EXPECT_EQ(data_buffer[0], 1);
EXPECT_EQ(data_buffer[1], 3);
auto arrow_array = ImportArray(&array, uint8());
ARROW_EXPECT_OK(arrow_array);
auto builder = UInt8Builder();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.Append(3));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToDoubleArray) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DOUBLE), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 3), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, 3.14), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, std::numeric_limits<float>::max()),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, NAN), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, INFINITY), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, -INFINITY), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, -1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, 0), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 11);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const double*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0b11111001);
EXPECT_EQ(validity_buffer[1], 0b00000111);
EXPECT_EQ(data_buffer[0], 1);
EXPECT_EQ(data_buffer[1], 0);
EXPECT_EQ(data_buffer[2], 0);
EXPECT_EQ(data_buffer[3], 3);
EXPECT_DOUBLE_EQ(data_buffer[4], 3.14);
EXPECT_FLOAT_EQ(static_cast<float>(data_buffer[4]), static_cast<float>(3.14));
EXPECT_FLOAT_EQ(static_cast<float>(data_buffer[5]), std::numeric_limits<float>::max());
EXPECT_TRUE(std::isnan(data_buffer[6])) << data_buffer[6];
EXPECT_FLOAT_EQ(static_cast<float>(data_buffer[7]), INFINITY);
EXPECT_FLOAT_EQ(static_cast<float>(data_buffer[8]), -INFINITY);
EXPECT_FLOAT_EQ(static_cast<float>(data_buffer[9]), -1);
EXPECT_FLOAT_EQ(static_cast<float>(data_buffer[10]), 0);
auto arrow_array = ImportArray(&array, float64());
ARROW_EXPECT_OK(arrow_array);
auto builder = DoubleBuilder();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(3));
ARROW_EXPECT_OK(builder.Append(3.14));
ARROW_EXPECT_OK(builder.Append(std::numeric_limits<float>::max()));
ARROW_EXPECT_OK(builder.Append(NAN));
ARROW_EXPECT_OK(builder.Append(INFINITY));
ARROW_EXPECT_OK(builder.Append(-INFINITY));
ARROW_EXPECT_OK(builder.Append(-1));
ARROW_EXPECT_OK(builder.Append(0));
auto expected_array = builder.Finish();
auto options = arrow::EqualOptions::Defaults().nans_equal(true);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe(), options));
}
TEST(ArrayTest, ArrayTestAppendToFloatArray) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_FLOAT), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 3), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, 3.14), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, std::numeric_limits<float>::max()),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, NAN), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, INFINITY), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, -INFINITY), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, -1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendDouble(&array, 0), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 11);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const float*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0b11111001);
EXPECT_EQ(validity_buffer[1], 0b00000111);
EXPECT_EQ(data_buffer[0], 1);
EXPECT_EQ(data_buffer[1], 0);
EXPECT_EQ(data_buffer[2], 0);
EXPECT_EQ(data_buffer[3], 3);
EXPECT_FLOAT_EQ(data_buffer[4], static_cast<float>(3.14));
EXPECT_FLOAT_EQ(data_buffer[5], std::numeric_limits<float>::max());
EXPECT_TRUE(std::isnan(data_buffer[6])) << data_buffer[6];
EXPECT_FLOAT_EQ(data_buffer[7], INFINITY);
EXPECT_FLOAT_EQ(data_buffer[8], -INFINITY);
EXPECT_FLOAT_EQ(data_buffer[9], -1);
EXPECT_FLOAT_EQ(data_buffer[10], 0);
auto arrow_array = ImportArray(&array, float32());
ARROW_EXPECT_OK(arrow_array);
auto builder = FloatBuilder();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(3));
ARROW_EXPECT_OK(builder.Append(static_cast<float>(3.14)));
ARROW_EXPECT_OK(builder.Append(std::numeric_limits<float>::max()));
ARROW_EXPECT_OK(builder.Append(NAN));
ARROW_EXPECT_OK(builder.Append(INFINITY));
ARROW_EXPECT_OK(builder.Append(-INFINITY));
ARROW_EXPECT_OK(builder.Append(-1));
ARROW_EXPECT_OK(builder.Append(0));
auto expected_array = builder.Finish();
auto options = arrow::EqualOptions::Defaults().nans_equal(true);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe(), options));
}
TEST(ArrayTest, ArrayTestAppendToBoolArray) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_BOOL), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendUInt(&array, 0), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 4);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0x01 | 0x08);
EXPECT_EQ(ArrowBitGet(data_buffer, 0), 0x01);
EXPECT_EQ(ArrowBitGet(data_buffer, 1), 0x00);
EXPECT_EQ(ArrowBitGet(data_buffer, 2), 0x00);
EXPECT_EQ(ArrowBitGet(data_buffer, 3), 0x00);
auto arrow_array = ImportArray(&array, boolean());
ARROW_EXPECT_OK(arrow_array);
auto builder = BooleanBuilder();
ARROW_EXPECT_OK(builder.Append(true));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(false));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToLargeStringArray) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LARGE_STRING), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(&array, 1)->capacity_bytes, (5 + 1) * sizeof(int64_t));
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("1234")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendString(&array, ArrowCharView("56789")), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 5);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto offset_buffer = reinterpret_cast<const int64_t*>(array.buffers[1]);
auto data_buffer = reinterpret_cast<const char*>(array.buffers[2]);
EXPECT_EQ(validity_buffer[0], 0b00011001);
EXPECT_EQ(offset_buffer[0], 0);
EXPECT_EQ(offset_buffer[1], 4);
EXPECT_EQ(offset_buffer[2], 4);
EXPECT_EQ(offset_buffer[3], 4);
EXPECT_EQ(offset_buffer[4], 9);
EXPECT_EQ(memcmp(data_buffer, "123456789", 9), 0);
auto arrow_array = ImportArray(&array, large_utf8());
ARROW_EXPECT_OK(arrow_array);
auto builder = LargeStringBuilder();
ARROW_EXPECT_OK(builder.Append("1234"));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append("56789"));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToFixedSizeBinaryArray) {
struct ArrowArray array;
struct ArrowSchema schema;
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_BINARY, 5),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(&array, 1)->capacity_bytes, 5 * 5);
EXPECT_EQ(ArrowArrayAppendBytes(&array, {{"12345"}, 5}), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendBytes(&array, {{"67890"}, 5}), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 5);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const char*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0b00011001);
char expected_data[] = {'1', '2', '3', '4', '5', 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '6', '7', '8',
'9', '0', 0x00, 0x00, 0x00, 0x00, 0x00};
EXPECT_EQ(memcmp(data_buffer, expected_data, 25), 0);
auto arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(arrow_array);
auto builder = FixedSizeBinaryBuilder(fixed_size_binary(5));
ARROW_EXPECT_OK(builder.Append("12345"));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append("67890"));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
ARROW_EXPECT_OK(expected_array);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToBinaryArrayErrors) {
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_BINARY), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
struct ArrowBufferView item;
item.data.as_char = "";
item.size_bytes = static_cast<int64_t>(INT_MAX) + 1;
EXPECT_EQ(ArrowArrayAppendBytes(&array, item), EOVERFLOW);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayTestAppendToIntervalArrayYearMonth) {
struct ArrowArray array;
const int32_t months = 42;
struct ArrowInterval interval;
ArrowIntervalInit(&interval, ArrowType::NANOARROW_TYPE_INTERVAL_MONTHS);
interval.months = 42;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INTERVAL_MONTHS), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInterval(&array, &interval), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 2);
EXPECT_EQ(array.null_count, 1);
auto data_buffer = reinterpret_cast<const int32_t*>(array.buffers[1]);
EXPECT_EQ(data_buffer[0], months);
auto arrow_array = ImportArray(&array, month_interval());
ARROW_EXPECT_OK(arrow_array);
// TODO: arrow does not have a builder for MonthIntervals
// so no comparison is done after creating the array
}
TEST(ArrayTest, ArrayTestAppendToIntervalArrayDayTime) {
struct ArrowArray array;
struct ArrowInterval interval;
ArrowIntervalInit(&interval, ArrowType::NANOARROW_TYPE_INTERVAL_DAY_TIME);
interval.days = 42;
interval.ms = 42;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INTERVAL_DAY_TIME),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInterval(&array, &interval), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 2);
EXPECT_EQ(array.null_count, 1);
auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
EXPECT_EQ(memcmp(data_buffer, &interval.days, 4), 0);
EXPECT_EQ(memcmp(data_buffer + sizeof(interval.days), &interval.ms, 4), 0);
auto arrow_array = ImportArray(&array, day_time_interval());
ARROW_EXPECT_OK(arrow_array);
auto builder = DayTimeIntervalBuilder();
DayTimeIntervalType::DayMilliseconds dm = {42, 42};
ARROW_EXPECT_OK(builder.Append(dm));
ARROW_EXPECT_OK(builder.AppendNulls(1));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToIntervalArrayMonthDayNano) {
struct ArrowArray array;
struct ArrowInterval interval;
ArrowIntervalInit(&interval, ArrowType::NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO);
interval.months = 2;
interval.days = 12;
interval.ns = 42;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendInterval(&array, &interval), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
struct ArrowInterval second;
ArrowIntervalInit(&second, ArrowType::NANOARROW_TYPE_INTERVAL_MONTH_DAY_NANO);
second.months = 1;
second.days = 1;
second.ns = 1;
EXPECT_EQ(ArrowArrayAppendInterval(&array, &second), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 4);
EXPECT_EQ(array.null_count, 2);
auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
EXPECT_EQ(memcmp(data_buffer, &interval.months, sizeof(interval.months)), 0);
EXPECT_EQ(memcmp(data_buffer + sizeof(interval.months), &interval.days,
sizeof(interval.days)),
0);
EXPECT_EQ(memcmp(data_buffer + sizeof(interval.months) + sizeof(interval.days),
&interval.ns, sizeof(interval.ns)),
0);
auto arrow_array = ImportArray(&array, month_day_nano_interval());
ARROW_EXPECT_OK(arrow_array);
auto builder = MonthDayNanoIntervalBuilder();
MonthDayNanoIntervalType::MonthDayNanos mdn = {2, 12, 42};
ARROW_EXPECT_OK(builder.Append(mdn));
ARROW_EXPECT_OK(builder.AppendNulls(1));
MonthDayNanoIntervalType::MonthDayNanos ones = {1, 1, 1};
ARROW_EXPECT_OK(builder.Append(ones));
ARROW_EXPECT_OK(builder.AppendNulls(1));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToDecimal128Array) {
struct ArrowArray array;
struct ArrowDecimal decimal;
ArrowDecimalInit(&decimal, 128, 10, 3);
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DECIMAL128), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ArrowDecimalSetInt(&decimal, 12345);
EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
ArrowDecimalSetInt(&decimal, -67890);
EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 4);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0b00001001);
ArrowDecimalSetInt(&decimal, 12345);
EXPECT_EQ(memcmp(data_buffer, decimal.words, 16), 0);
ArrowDecimalSetInt(&decimal, -67890);
EXPECT_EQ(memcmp(data_buffer + 3 * 16, decimal.words, 16), 0);
auto arrow_array = ImportArray(&array, decimal128(10, 3));
ARROW_EXPECT_OK(arrow_array);
auto builder = Decimal128Builder(decimal128(10, 3));
ARROW_EXPECT_OK(builder.Append(*Decimal128::FromString("12.345")));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(*Decimal128::FromString("-67.890")));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToDecimal256Array) {
struct ArrowArray array;
struct ArrowDecimal decimal;
ArrowDecimalInit(&decimal, 256, 10, 3);
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_DECIMAL256), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ArrowDecimalSetInt(&decimal, 12345);
EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
ArrowDecimalSetInt(&decimal, -67890);
EXPECT_EQ(ArrowArrayAppendDecimal(&array, &decimal), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(array.length, 4);
EXPECT_EQ(array.null_count, 2);
auto validity_buffer = reinterpret_cast<const uint8_t*>(array.buffers[0]);
auto data_buffer = reinterpret_cast<const uint8_t*>(array.buffers[1]);
EXPECT_EQ(validity_buffer[0], 0b00001001);
ArrowDecimalSetInt(&decimal, 12345);
EXPECT_EQ(memcmp(data_buffer, decimal.words, 32), 0);
ArrowDecimalSetInt(&decimal, -67890);
EXPECT_EQ(memcmp(data_buffer + 3 * 32, decimal.words, 32), 0);
auto arrow_array = ImportArray(&array, decimal256(10, 3));
ARROW_EXPECT_OK(arrow_array);
auto builder = Decimal256Builder(decimal256(10, 3));
ARROW_EXPECT_OK(builder.Append(*Decimal256::FromString("12.345")));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(*Decimal256::FromString("-67.890")));
auto expected_array = builder.Finish();
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToListArray) {
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowError error;
ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve recursively without erroring
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(array.children[0], 1)->capacity_bytes, 0);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 456), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 789), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
// Make sure number of children is checked at finish
array.n_children = 0;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(ArrowErrorMessage(&error),
"Expected 1 child of list array but found 0 child arrays");
array.n_children = 1;
// Make sure final child size is checked at finish
array.children[0]->length = array.children[0]->length - 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(
ArrowErrorMessage(&error),
"Expected child of list array to have length >= 3 but found array with length 2");
array.children[0]->length = array.children[0]->length + 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
auto arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(arrow_array);
auto child_builder = std::make_shared<Int64Builder>();
auto builder = ListBuilder(default_memory_pool(), child_builder, list(int64()));
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(child_builder->Append(123));
ARROW_EXPECT_OK(builder.AppendNull());
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(child_builder->Append(456));
ARROW_EXPECT_OK(child_builder->Append(789));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
ARROW_EXPECT_OK(expected_array);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToLargeListArray) {
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowError error;
ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_LARGE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve recursively without erroring
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(array.children[0], 1)->capacity_bytes, 0);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 456), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 789), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
// Make sure number of children is checked at finish
array.n_children = 0;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(ArrowErrorMessage(&error),
"Expected 1 child of large_list array but found 0 child arrays");
array.n_children = 1;
// Make sure final child size is checked at finish
array.children[0]->length = array.children[0]->length - 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(
ArrowErrorMessage(&error),
"Expected child of large list array to have length >= 3 but found array with "
"length 2");
array.children[0]->length = array.children[0]->length + 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
auto arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(arrow_array);
auto child_builder = std::make_shared<Int64Builder>();
auto builder =
LargeListBuilder(default_memory_pool(), child_builder, large_list(int64()));
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(child_builder->Append(123));
ARROW_EXPECT_OK(builder.AppendNull());
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(child_builder->Append(456));
ARROW_EXPECT_OK(child_builder->Append(789));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
ARROW_EXPECT_OK(expected_array);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToMapArray) {
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowError error;
ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_MAP), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0]->children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0]->children[1], NANOARROW_TYPE_STRING),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve recursively without erroring
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(array.children[0], 1)->capacity_bytes, 0);
struct ArrowStringView string_value = ArrowCharView("foobar");
ASSERT_EQ(ArrowArrayAppendInt(array.children[0]->children[0], 123), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.children[0]->children[1], string_value),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(array.children[0]), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
// Make sure number of children is checked at finish
array.n_children = 0;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(ArrowErrorMessage(&error),
"Expected 1 child of map array but found 0 child arrays");
array.n_children = 1;
// Make sure final child size is checked at finish
array.children[0]->length = array.children[0]->length - 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(
ArrowErrorMessage(&error),
"Expected child of map array to have length >= 1 but found array with length 0");
array.children[0]->length = array.children[0]->length + 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
auto maybe_arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(maybe_arrow_array);
auto arrow_array = std::move(maybe_arrow_array).MoveValueUnsafe();
auto key_builder = std::make_shared<Int32Builder>();
auto value_builder = std::make_shared<StringBuilder>();
auto builder =
MapBuilder(default_memory_pool(), key_builder, value_builder, map(int32(), utf8()));
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(key_builder->Append(123));
ARROW_EXPECT_OK(value_builder->Append("foobar"));
ARROW_EXPECT_OK(builder.AppendNull());
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto maybe_expected_array = builder.Finish();
ARROW_EXPECT_OK(maybe_expected_array);
auto expected_array = std::move(maybe_expected_array).MoveValueUnsafe();
EXPECT_TRUE(arrow_array->Equals(expected_array));
}
TEST(ArrayTest, ArrayTestAppendToFixedSizeListArray) {
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowError error;
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 2),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve recursively
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(array.children[0], 1)->capacity_bytes,
2 * 5 * sizeof(int64_t));
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 456), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 789), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 12), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
// Make sure number of children is checked at finish
array.n_children = 0;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(ArrowErrorMessage(&error),
"Expected 1 child of fixed_size_list array but found 0 child arrays");
array.n_children = 1;
// Make sure final child size is checked at finish
array.children[0]->length = array.children[0]->length - 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), EINVAL);
EXPECT_STREQ(
ArrowErrorMessage(&error),
"Expected child of fixed_size_list array to have length >= 8 but found array "
"with length 7");
array.children[0]->length = array.children[0]->length + 1;
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
auto arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(arrow_array);
auto child_builder = std::make_shared<Int64Builder>();
auto builder = FixedSizeListBuilder(default_memory_pool(), child_builder,
fixed_size_list(int64(), 2));
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(child_builder->Append(123));
ARROW_EXPECT_OK(child_builder->Append(456));
ARROW_EXPECT_OK(builder.AppendNull());
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(child_builder->Append(789));
ARROW_EXPECT_OK(child_builder->Append(12));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
ARROW_EXPECT_OK(expected_array);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToListArrayErrors) {
struct ArrowArray array;
struct ArrowSchema schema;
ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
array.children[0]->length = static_cast<int64_t>(INT32_MAX) + 1;
EXPECT_EQ(ArrowArrayFinishElement(&array), EOVERFLOW);
ArrowArrayRelease(&array);
ArrowSchemaRelease(&schema);
}
TEST(ArrayTest, ArrayTestAppendToStructArray) {
struct ArrowArray array;
struct ArrowSchema schema;
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeStruct(&schema, 1), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "col1"), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
// Check that we can reserve recursively
ASSERT_EQ(ArrowArrayReserve(&array, 5), NANOARROW_OK);
EXPECT_EQ(ArrowArrayBuffer(array.children[0], 1)->capacity_bytes, 5 * sizeof(int64_t));
// Wrong child length
EXPECT_EQ(ArrowArrayFinishElement(&array), EINVAL);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 456), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
auto arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(arrow_array);
auto child_builder = std::make_shared<Int64Builder>();
auto builder = StructBuilder(struct_({field("col1", int64())}), default_memory_pool(),
{child_builder});
ARROW_EXPECT_OK(child_builder->Append(123));
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(builder.AppendNull());
ARROW_EXPECT_OK(child_builder->Append(456));
ARROW_EXPECT_OK(builder.Append());
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
ARROW_EXPECT_OK(expected_array);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestUnionUtils) {
// Check length calculation with nullptr
EXPECT_EQ(_ArrowParseUnionTypeIds("", nullptr), 0);
EXPECT_EQ(_ArrowParseUnionTypeIds("0", nullptr), 1);
EXPECT_EQ(_ArrowParseUnionTypeIds("0,1", nullptr), 2);
// Invalid
EXPECT_EQ(_ArrowParseUnionTypeIds("0,1,", nullptr), -1);
EXPECT_EQ(_ArrowParseUnionTypeIds("0,1A", nullptr), -1);
EXPECT_EQ(_ArrowParseUnionTypeIds("128", nullptr), -1);
EXPECT_EQ(_ArrowParseUnionTypeIds("-1", nullptr), -1);
// Check output
int8_t type_ids[] = {-1, -1, -1, -1};
EXPECT_EQ(_ArrowParseUnionTypeIds("4,5,6,7", type_ids), 4);
EXPECT_EQ(type_ids[0], 4);
EXPECT_EQ(type_ids[1], 5);
EXPECT_EQ(type_ids[2], 6);
EXPECT_EQ(type_ids[3], 7);
// Check the "ids will equal child indices" checker
EXPECT_TRUE(_ArrowUnionTypeIdsWillEqualChildIndices("", 0));
EXPECT_TRUE(_ArrowUnionTypeIdsWillEqualChildIndices("0", 1));
EXPECT_TRUE(_ArrowUnionTypeIdsWillEqualChildIndices("0,1", 2));
EXPECT_FALSE(_ArrowUnionTypeIdsWillEqualChildIndices("0,1", 1));
EXPECT_FALSE(_ArrowUnionTypeIdsWillEqualChildIndices(",", 0));
EXPECT_FALSE(_ArrowUnionTypeIdsWillEqualChildIndices("1", 1));
EXPECT_FALSE(_ArrowUnionTypeIdsWillEqualChildIndices("0,2", 2));
EXPECT_FALSE(_ArrowUnionTypeIdsWillEqualChildIndices("0,2", 2));
}
TEST(ArrayTest, ArrayTestAppendToDenseUnionArray) {
struct ArrowArray array;
struct ArrowSchema schema;
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_DENSE_UNION, 2),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "integers"), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetName(schema.children[1], "strings"), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishUnionElement(&array, 0), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.children[1], ArrowCharView("one twenty four")),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
auto arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(arrow_array);
auto child_builder_int = std::make_shared<Int64Builder>();
auto child_builder_string = std::make_shared<StringBuilder>();
std::vector<std::shared_ptr<ArrayBuilder>> children = {child_builder_int,
child_builder_string};
auto builder = DenseUnionBuilder(default_memory_pool(), children,
arrow_array.ValueUnsafe()->type());
ARROW_EXPECT_OK(builder.Append(0));
ARROW_EXPECT_OK(child_builder_int->Append(123));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(child_builder_string->Append("one twenty four"));
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
ARROW_EXPECT_OK(expected_array);
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToSparseUnionArray) {
struct ArrowArray array;
struct ArrowSchema schema;
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_SPARSE_UNION, 2),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT64), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetName(schema.children[0], "integers"), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetName(schema.children[1], "strings"), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishUnionElement(&array, 0), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendNull(&array, 2), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.children[1], ArrowCharView("one twenty four")),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayAppendEmpty(&array, 1), NANOARROW_OK);
EXPECT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
auto arrow_array = ImportArray(&array, &schema);
ARROW_EXPECT_OK(arrow_array);
auto child_builder_int = std::make_shared<Int64Builder>();
auto child_builder_string = std::make_shared<StringBuilder>();
std::vector<std::shared_ptr<ArrayBuilder>> children = {child_builder_int,
child_builder_string};
auto builder = SparseUnionBuilder(default_memory_pool(), children,
arrow_array.ValueUnsafe()->type());
// Arrow's SparseUnionBuilder requires explicit empty value appends?
ARROW_EXPECT_OK(builder.Append(0));
ARROW_EXPECT_OK(child_builder_int->Append(123));
ARROW_EXPECT_OK(child_builder_string->AppendEmptyValue());
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(child_builder_string->Append("one twenty four"));
ARROW_EXPECT_OK(child_builder_int->AppendEmptyValue());
ARROW_EXPECT_OK(builder.AppendEmptyValue());
auto expected_array = builder.Finish();
ARROW_EXPECT_OK(expected_array);
EXPECT_EQ(arrow_array.ValueUnsafe()->ToString(),
expected_array.ValueUnsafe()->ToString());
EXPECT_TRUE(arrow_array.ValueUnsafe()->Equals(expected_array.ValueUnsafe()));
}
TEST(ArrayTest, ArrayTestAppendToUnionArrayErrors) {
struct ArrowArray array;
struct ArrowSchema schema;
// Make an valid union that won't work during appending (because
// the type_id != child_index)
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_DENSE_UNION, 1),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+us:1"), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayStartAppending(&array), EINVAL);
ArrowSchemaRelease(&schema);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayViewTestBasic) {
struct ArrowArrayView array_view;
struct ArrowError error;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_INT32);
EXPECT_EQ(array_view.array, nullptr);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_INT32);
EXPECT_EQ(array_view.layout.buffer_type[0], NANOARROW_BUFFER_TYPE_VALIDITY);
EXPECT_EQ(array_view.layout.buffer_type[1], NANOARROW_BUFFER_TYPE_DATA);
EXPECT_EQ(array_view.layout.element_size_bits[0], 1);
EXPECT_EQ(array_view.layout.element_size_bits[1], 32);
ArrowArrayViewSetLength(&array_view, 5);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 5 * sizeof(int32_t));
struct ArrowArray array;
// Build with no validity buffer
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 11), NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 12), NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 13), NANOARROW_OK);
array.length = 3;
array.null_count = 0;
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 3 * sizeof(int32_t));
EXPECT_EQ(array_view.buffer_views[1].data.as_int32[0], 11);
EXPECT_EQ(array_view.buffer_views[1].data.as_int32[1], 12);
EXPECT_EQ(array_view.buffer_views[1].data.as_int32[2], 13);
// Build with validity buffer
ASSERT_EQ(ArrowBitmapAppend(ArrowArrayValidityBitmap(&array), 1, 3), NANOARROW_OK);
array.null_count = -1;
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 3 * sizeof(int32_t));
// Expect error for bad offset + length
array.length = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected length >= 0 but found length -1");
array.length = 3;
array.offset = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected offset >= 0 but found offset -1");
array.offset = 0;
// Expect error for the wrong number of buffers
ArrowArrayViewReset(&array_view);
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRING);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestMove) {
struct ArrowArrayView array_view;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRING);
ASSERT_EQ(array_view.storage_type, NANOARROW_TYPE_STRING);
struct ArrowArrayView array_view2;
ArrowArrayViewInitFromType(&array_view2, NANOARROW_TYPE_UNINITIALIZED);
ASSERT_EQ(array_view2.storage_type, NANOARROW_TYPE_UNINITIALIZED);
ArrowArrayViewMove(&array_view, &array_view2);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_UNINITIALIZED);
EXPECT_EQ(array_view2.storage_type, NANOARROW_TYPE_STRING);
ArrowArrayViewReset(&array_view2);
}
TEST(ArrayTest, ArrayViewTestString) {
struct ArrowArrayView array_view;
struct ArrowError error;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRING);
EXPECT_EQ(array_view.array, nullptr);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_STRING);
EXPECT_EQ(array_view.layout.buffer_type[0], NANOARROW_BUFFER_TYPE_VALIDITY);
EXPECT_EQ(array_view.layout.buffer_type[1], NANOARROW_BUFFER_TYPE_DATA_OFFSET);
EXPECT_EQ(array_view.layout.buffer_type[2], NANOARROW_BUFFER_TYPE_DATA);
EXPECT_EQ(array_view.layout.element_size_bits[0], 1);
EXPECT_EQ(array_view.layout.element_size_bits[1], 32);
EXPECT_EQ(array_view.layout.element_size_bits[2], 0);
// Can't assume offset buffer size > 0 if length == 0
ArrowArrayViewSetLength(&array_view, 0);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
ArrowArrayViewSetLength(&array_view, 5);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, (5 + 1) * sizeof(int32_t));
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
struct ArrowArray array;
// Build + check zero length using append mode
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
ArrowArrayRelease(&array);
// Build + check zero length
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRING), NANOARROW_OK);
array.null_count = 0;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
// Build non-zero length (the array ["abcd", "efg"])
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 0), NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 4), NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(&array, 1), 7), NANOARROW_OK);
ASSERT_EQ(ArrowBufferReserve(ArrowArrayBuffer(&array, 2), 7), NANOARROW_OK);
ArrowBufferAppendUnsafe(ArrowArrayBuffer(&array, 2), "abcd", 4);
ArrowBufferAppendUnsafe(ArrowArrayBuffer(&array, 2), "efg", 3);
array.length = 2;
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, (1 + array.length) * sizeof(int32_t));
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 7);
// Expect error for offsets that will cause bad access
int32_t* offsets =
const_cast<int32_t*>(reinterpret_cast<const int32_t*>(array.buffers[1]));
offsets[0] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected first offset >= 0 but found -1");
offsets[0] = 0;
offsets[1] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "[1] Expected element size >= 0");
// Check sequential offsets whose diff causes overflow
offsets[1] = 2080374784;
offsets[2] = INT_MIN;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "[2] Expected element size >= 0");
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestLargeString) {
struct ArrowArrayView array_view;
struct ArrowError error;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LARGE_STRING);
EXPECT_EQ(array_view.array, nullptr);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_LARGE_STRING);
EXPECT_EQ(array_view.layout.buffer_type[0], NANOARROW_BUFFER_TYPE_VALIDITY);
EXPECT_EQ(array_view.layout.buffer_type[1], NANOARROW_BUFFER_TYPE_DATA_OFFSET);
EXPECT_EQ(array_view.layout.buffer_type[2], NANOARROW_BUFFER_TYPE_DATA);
EXPECT_EQ(array_view.layout.element_size_bits[0], 1);
EXPECT_EQ(array_view.layout.element_size_bits[1], 64);
EXPECT_EQ(array_view.layout.element_size_bits[2], 0);
// Can't assume offset buffer size > 0 if length == 0
ArrowArrayViewSetLength(&array_view, 0);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
ArrowArrayViewSetLength(&array_view, 5);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, (5 + 1) * sizeof(int64_t));
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
struct ArrowArray array;
// Build + check zero length using append mode
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LARGE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
ArrowArrayRelease(&array);
// Build + check zero length
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LARGE_STRING), NANOARROW_OK);
array.null_count = 0;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 0);
// Build non-zero length (the array ["abcd"])
ASSERT_EQ(ArrowBufferAppendInt64(ArrowArrayBuffer(&array, 1), 0), NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt64(ArrowArrayBuffer(&array, 1), 4), NANOARROW_OK);
ASSERT_EQ(ArrowBufferReserve(ArrowArrayBuffer(&array, 2), 4), NANOARROW_OK);
ArrowBufferAppendUnsafe(ArrowArrayBuffer(&array, 2), "abcd", 4);
array.length = 1;
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 0);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, (1 + 1) * sizeof(int64_t));
EXPECT_EQ(array_view.buffer_views[2].size_bytes, 4);
// Expect error for offsets that will cause bad access
int64_t* offsets =
const_cast<int64_t*>(reinterpret_cast<const int64_t*>(array.buffers[1]));
offsets[0] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected first offset >= 0 but found -1");
offsets[0] = 0;
offsets[1] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "[1] Expected element size >= 0");
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestStruct) {
struct ArrowArrayView array_view;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_STRUCT);
EXPECT_EQ(array_view.array, nullptr);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_STRUCT);
EXPECT_EQ(array_view.layout.buffer_type[0], NANOARROW_BUFFER_TYPE_VALIDITY);
EXPECT_EQ(array_view.layout.element_size_bits[0], 1);
// Expect error for out-of-memory
EXPECT_EQ(ArrowArrayViewAllocateChildren(
&array_view, std::numeric_limits<int64_t>::max() / sizeof(void*)),
ENOMEM);
EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 2), NANOARROW_OK);
EXPECT_EQ(array_view.n_children, 2);
ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
ArrowArrayViewInitFromType(array_view.children[1], NANOARROW_TYPE_NA);
EXPECT_EQ(array_view.children[1]->storage_type, NANOARROW_TYPE_NA);
ArrowArrayViewSetLength(&array_view, 5);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.children[0]->buffer_views[1].size_bytes, 5 * sizeof(int32_t));
// Except error for attempting to allocate a children array that already exists
EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), EINVAL);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestList) {
struct ArrowArrayView array_view;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LIST);
EXPECT_EQ(array_view.array, nullptr);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_LIST);
EXPECT_EQ(array_view.layout.buffer_type[0], NANOARROW_BUFFER_TYPE_VALIDITY);
EXPECT_EQ(array_view.layout.element_size_bits[0], 1);
EXPECT_EQ(array_view.layout.buffer_type[1], NANOARROW_BUFFER_TYPE_DATA_OFFSET);
EXPECT_EQ(array_view.layout.element_size_bits[1], 8 * sizeof(int32_t));
EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
EXPECT_EQ(array_view.n_children, 1);
ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
ArrowArrayViewSetLength(&array_view, 5);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, (5 + 1) * sizeof(int32_t));
// Build a valid array
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 1234), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
// Expect error for offsets that will cause bad access
struct ArrowError error;
int32_t* offsets =
const_cast<int32_t*>(reinterpret_cast<const int32_t*>(array.buffers[1]));
offsets[0] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected first offset >= 0 but found -1");
offsets[0] = 0;
offsets[1] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "[1] Expected element size >= 0");
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestListGet) {
struct ArrowArrayView array_view;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LIST);
EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
// Build a valid array
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 1234), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 42), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 2), 1);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 3), 2);
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestLargeListGet) {
struct ArrowArrayView array_view;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LARGE_LIST);
EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
// Build a valid array
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LARGE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 1234), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 42), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 2), 1);
EXPECT_EQ(ArrowArrayViewListChildOffset(&array_view, 3), 2);
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestLargeList) {
struct ArrowArrayView array_view;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_LARGE_LIST);
EXPECT_EQ(array_view.array, nullptr);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_LARGE_LIST);
EXPECT_EQ(array_view.layout.buffer_type[0], NANOARROW_BUFFER_TYPE_VALIDITY);
EXPECT_EQ(array_view.layout.element_size_bits[0], 1);
EXPECT_EQ(array_view.layout.buffer_type[1], NANOARROW_BUFFER_TYPE_DATA_OFFSET);
EXPECT_EQ(array_view.layout.element_size_bits[1], 8 * sizeof(int64_t));
EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
EXPECT_EQ(array_view.n_children, 1);
ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
ArrowArrayViewSetLength(&array_view, 5);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, (5 + 1) * sizeof(int64_t));
// Build a valid array
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_LARGE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 1234), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishElement(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
// Expect error for offsets that will cause bad access
struct ArrowError error;
int64_t* offsets =
const_cast<int64_t*>(reinterpret_cast<const int64_t*>(array.buffers[1]));
offsets[0] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected first offset >= 0 but found -1");
offsets[0] = 0;
offsets[1] = -1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "[1] Expected element size >= 0");
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestFixedSizeList) {
struct ArrowArrayView array_view;
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_FIXED_SIZE_LIST);
array_view.layout.child_size_elements = 3;
EXPECT_EQ(array_view.array, nullptr);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_FIXED_SIZE_LIST);
EXPECT_EQ(array_view.layout.buffer_type[0], NANOARROW_BUFFER_TYPE_VALIDITY);
EXPECT_EQ(array_view.layout.element_size_bits[0], 1);
EXPECT_EQ(ArrowArrayViewAllocateChildren(&array_view, 1), NANOARROW_OK);
EXPECT_EQ(array_view.n_children, 1);
ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
ArrowArrayViewSetLength(&array_view, 5);
EXPECT_EQ(array_view.buffer_views[0].size_bytes, 1);
EXPECT_EQ(array_view.children[0]->buffer_views[1].size_bytes, 15 * sizeof(int32_t));
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestStructArray) {
struct ArrowArrayView array_view;
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowError error;
ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaAllocateChildren(&schema, 1), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaInitFromType(schema.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error), NANOARROW_OK);
EXPECT_EQ(array_view.n_children, 1);
EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_STRUCT), NANOARROW_OK);
// Expect error for the wrong number of children
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
// Expect error for the wrong number of child elements
array.length = 1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(array.children[0], 1), 123),
NANOARROW_OK);
array.children[0]->length = 1;
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.children[0]->buffer_views[1].size_bytes, sizeof(int32_t));
EXPECT_EQ(array_view.children[0]->buffer_views[1].data.as_int32[0], 123);
ArrowArrayViewReset(&array_view);
ArrowSchemaRelease(&schema);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayViewTestFixedSizeListArray) {
struct ArrowArrayView array_view;
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowError error;
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeFixedSize(&schema, NANOARROW_TYPE_FIXED_SIZE_LIST, 3),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error), NANOARROW_OK);
EXPECT_EQ(array_view.n_children, 1);
EXPECT_EQ(array_view.children[0]->storage_type, NANOARROW_TYPE_INT32);
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_FIXED_SIZE_LIST), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAllocateChildren(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromType(array.children[0], NANOARROW_TYPE_INT32),
NANOARROW_OK);
// Expect error for the wrong number of child elements
array.length = 1;
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(array.children[0], 1), 123),
NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(array.children[0], 1), 456),
NANOARROW_OK);
ASSERT_EQ(ArrowBufferAppendInt32(ArrowArrayBuffer(array.children[0], 1), 789),
NANOARROW_OK);
array.children[0]->length = 3;
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(array_view.children[0]->buffer_views[1].size_bytes, 3 * sizeof(int32_t));
EXPECT_EQ(array_view.children[0]->buffer_views[1].data.as_int32[0], 123);
ArrowArrayViewReset(&array_view);
ArrowSchemaRelease(&schema);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayViewTestDictionary) {
struct ArrowSchema schema;
struct ArrowArrayView array_view;
ASSERT_EQ(ArrowSchemaInitFromType(&schema, NANOARROW_TYPE_INT32), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaAllocateDictionary(&schema), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaInitFromType(schema.dictionary, NANOARROW_TYPE_STRING),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), NANOARROW_OK);
EXPECT_EQ(array_view.storage_type, NANOARROW_TYPE_INT32);
ASSERT_NE(array_view.dictionary, nullptr);
EXPECT_EQ(array_view.dictionary->storage_type, NANOARROW_TYPE_STRING);
// Build a dictionary array
struct ArrowArray array;
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.dictionary, ArrowCharView("abc")), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.dictionary, ArrowCharView("def")), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(&array, 0), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(array_view.buffer_views[1].size_bytes, 2 * sizeof(int32_t));
EXPECT_EQ(array_view.dictionary->buffer_views[2].size_bytes, 6);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewGetIntUnsafe(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewGetIntUnsafe(&array_view, 1), 1);
struct ArrowStringView item;
item = ArrowArrayViewGetStringUnsafe(array_view.dictionary, 0);
EXPECT_EQ(std::string(item.data, item.size_bytes), "abc");
item = ArrowArrayViewGetStringUnsafe(array_view.dictionary, 1);
EXPECT_EQ(std::string(item.data, item.size_bytes), "def");
ArrowArrayRelease(&array);
// Setting a non-dictionary array should error
struct ArrowError error;
ASSERT_EQ(ArrowArrayInitFromType(&array, NANOARROW_TYPE_INT32), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected dictionary but found NULL");
ArrowArrayRelease(&array);
// Setting a dictionary array to a non-dictionary array view should error
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ArrowArrayViewReset(&array_view);
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_INT32);
EXPECT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), EINVAL);
EXPECT_STREQ(error.message, "Expected NULL dictionary but found dictionary member");
ArrowSchemaRelease(&schema);
ArrowArrayRelease(&array);
ArrowArrayViewReset(&array_view);
}
TEST(ArrayTest, ArrayViewTestUnionChildIndices) {
struct ArrowArrayView array_view;
struct ArrowArray array;
struct ArrowSchema schema;
// Build a simple union with one int and one string
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_DENSE_UNION, 2),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 0), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.children[1], ArrowCharView("one twenty four")),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
// The ArrayView for a union could in theroy be created without a schema.
// Currently FULL validation will fail here since we can't guarantee that
// these are valid.
ArrowArrayViewInitFromType(&array_view, NANOARROW_TYPE_DENSE_UNION);
ASSERT_EQ(ArrowArrayViewAllocateChildren(&array_view, 2), NANOARROW_OK);
ArrowArrayViewInitFromType(array_view.children[0], NANOARROW_TYPE_INT32);
ArrowArrayViewInitFromType(array_view.children[1], NANOARROW_TYPE_STRING);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
EINVAL);
EXPECT_EQ(ArrowArrayViewUnionTypeId(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionTypeId(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 1), 1);
ArrowArrayViewReset(&array_view);
// The test schema explicitly sets the type_ids 0,1 and this should validate properly
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewUnionTypeId(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionTypeId(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 1), 1);
// Check that bad type ids/offset are caught by validate full
struct ArrowError error;
int8_t* type_ids =
const_cast<int8_t*>(reinterpret_cast<const int8_t*>(array.buffers[0]));
int32_t* offsets =
const_cast<int32_t*>(reinterpret_cast<const int32_t*>(array.buffers[1]));
type_ids[0] = -1;
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message,
"[0] Expected buffer value between 0 and 1 but found value -1");
type_ids[0] = 0;
offsets[0] = -1;
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message,
"[0] Expected union offset for child id 0 to be between 0 and 1 but found "
"offset value -1");
offsets[0] = 0;
ArrowArrayViewReset(&array_view);
// Reversing the type ids should result in the same type ids but
// reversed child indices
ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+ud:1,0"), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewUnionTypeId(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionTypeId(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 0), 1);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 1), 0);
// Check that bad type ids are caught by validate full
type_ids[0] = -1;
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
EINVAL);
EXPECT_STREQ(error.message, "[0] Unexpected buffer value -1");
type_ids[0] = 0;
ArrowArrayViewReset(&array_view);
// Check the raw mapping in the array view for numbers that are easier to check
ASSERT_EQ(ArrowSchemaSetFormat(&schema, "+ud:6,2"), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), NANOARROW_OK);
EXPECT_EQ(array_view.union_type_id_map[6], 0);
EXPECT_EQ(array_view.union_type_id_map[2], 1);
EXPECT_EQ(array_view.union_type_id_map[128 + 0], 6);
EXPECT_EQ(array_view.union_type_id_map[128 + 1], 2);
ArrowArrayViewReset(&array_view);
ArrowSchemaRelease(&schema);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayViewTestDenseUnionGet) {
struct ArrowArrayView array_view;
struct ArrowArray array;
struct ArrowSchema schema;
// Build a simple union with one int and one string and one null int
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_DENSE_UNION, 2),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 0), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.children[1], ArrowCharView("one twenty four")),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
// Initialize the array view
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
// Check the values that will be used to index into children
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 2), 0);
// Check the values that will be used to index into the child arrays
EXPECT_EQ(ArrowArrayViewUnionChildOffset(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionChildOffset(&array_view, 1), 0);
EXPECT_EQ(ArrowArrayViewUnionChildOffset(&array_view, 2), 1);
// Union elements are "never null" (even if the corresponding child element is)
EXPECT_EQ(ArrowArrayViewIsNull(&array_view, 2), NANOARROW_OK);
ArrowArrayViewReset(&array_view);
ArrowSchemaRelease(&schema);
ArrowArrayRelease(&array);
}
TEST(ArrayTest, ArrayViewTestSparseUnionGet) {
struct ArrowArrayView array_view;
struct ArrowArray array;
struct ArrowSchema schema;
// Build a simple union with one int and one string and one null int
ArrowSchemaInit(&schema);
ASSERT_EQ(ArrowSchemaSetTypeUnion(&schema, NANOARROW_TYPE_SPARSE_UNION, 2),
NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[0], NANOARROW_TYPE_INT32), NANOARROW_OK);
ASSERT_EQ(ArrowSchemaSetType(schema.children[1], NANOARROW_TYPE_STRING), NANOARROW_OK);
ASSERT_EQ(ArrowArrayInitFromSchema(&array, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayStartAppending(&array), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendInt(array.children[0], 123), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 0), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendString(array.children[1], ArrowCharView("one twenty four")),
NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishUnionElement(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayAppendNull(&array, 1), NANOARROW_OK);
ASSERT_EQ(ArrowArrayFinishBuildingDefault(&array, nullptr), NANOARROW_OK);
// Initialize the array view
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, nullptr), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, nullptr), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, nullptr),
NANOARROW_OK);
// Check the values that will be used to index into children
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewUnionChildIndex(&array_view, 2), 0);
// Check the values that will be used to index into the child arrays
EXPECT_EQ(ArrowArrayViewUnionChildOffset(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewUnionChildOffset(&array_view, 1), 1);
EXPECT_EQ(ArrowArrayViewUnionChildOffset(&array_view, 2), 2);
// Union elements are "never null" (even if the corresponding child element is)
EXPECT_EQ(ArrowArrayViewIsNull(&array_view, 2), NANOARROW_OK);
ArrowArrayViewReset(&array_view);
ArrowSchemaRelease(&schema);
ArrowArrayRelease(&array);
}
template <typename TypeClass>
void TestGetFromNumericArrayView() {
struct ArrowArray array;
struct ArrowSchema schema;
struct ArrowArrayView array_view;
struct ArrowError error;
auto type = TypeTraits<TypeClass>::type_singleton();
// Array with nulls
auto builder = NumericBuilder<TypeClass>();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.AppendNulls(2));
ARROW_EXPECT_OK(builder.Append(4));
auto maybe_arrow_array = builder.Finish();
ARROW_EXPECT_OK(maybe_arrow_array);
auto arrow_array = maybe_arrow_array.ValueUnsafe();
ARROW_EXPECT_OK(ExportArray(*arrow_array, &array, &schema));
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewIsNull(&array_view, 2), 1);
EXPECT_EQ(ArrowArrayViewIsNull(&array_view, 3), 0);
EXPECT_EQ(ArrowArrayViewGetIntUnsafe(&array_view, 3), 4);
EXPECT_EQ(ArrowArrayViewGetUIntUnsafe(&array_view, 3), 4);
EXPECT_EQ(ArrowArrayViewGetDoubleUnsafe(&array_view, 3), 4.0);
auto string_view = ArrowArrayViewGetStringUnsafe(&array_view, 0);
EXPECT_EQ(string_view.data, nullptr);
EXPECT_EQ(string_view.size_bytes, 0);
auto buffer_view = ArrowArrayViewGetBytesUnsafe(&array_view, 0);
EXPECT_EQ(buffer_view.data.data, nullptr);
EXPECT_EQ(buffer_view.size_bytes, 0);
ArrowArrayViewReset(&array_view);
ArrowArrayRelease(&array);
ArrowSchemaRelease(&schema);
// Array without nulls (Arrow does not allocate the validity buffer)
builder = NumericBuilder<TypeClass>();
ARROW_EXPECT_OK(builder.Append(1));
ARROW_EXPECT_OK(builder.Append(2));
maybe_arrow_array = builder.Finish();
ARROW_EXPECT_OK(maybe_arrow_array);
arrow_array = maybe_arrow_array.ValueUnsafe();
ARROW_EXPECT_OK(ExportArray(*arrow_array, &array, &schema));
ASSERT_EQ(ArrowArrayViewInitFromSchema(&array_view, &schema, &error), NANOARROW_OK);
ASSERT_EQ(ArrowArrayViewSetArray(&array_view, &array, &error), NANOARROW_OK);
EXPECT_EQ(ArrowArrayViewValidate(&array_view, NANOARROW_VALIDATION_LEVEL_FULL, &error),
NANOARROW_OK);
// We're trying to test behavior with no validity buffer, so make sure that's true
ASSERT_EQ(array_view.buffer_views[0].data.data, nullptr);
EXPECT_EQ(ArrowArrayViewIsNull(&array_view, 0), 0);
EXPECT_EQ(ArrowArrayViewIsNull(&array_view, 1), 0);
EXPECT_EQ(ArrowArrayViewGetIntUnsafe(&array_view, 0), 1);
EXPECT_EQ(ArrowArrayViewGetUIntUnsafe(&array_view, 1), 2);
ArrowArrayViewReset(&array_view);
ArrowArrayRelease(&array);
ArrowSchemaRelease(&schema);
}
TEST(ArrayViewTest, ArrayViewTestGetNumeric) {
TestGetFromNumericArrayView<Int64Type>();
TestGetFromNumericArrayView<UInt64Type>();
TestGetFromNumericArrayView<Int32Type>();
TestGetFromNumericArrayView<UInt32Type>();
TestGetFromNumericArrayView<Int16Type>();
TestGetFromNumericArrayView<UInt32Type>();
TestGetFromNumericArrayView<Int8Type>();
TestGetFromNumericArrayView<UInt32Type>();
TestGetFromNumericArrayView<DoubleType>();
TestGetFromNumericArrayView<FloatType>();
}
template <typename BuilderClass>
void TestGetFromBinary(BuilderClass& builder) {
struct