1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17
18 #include <string>
19
20 #include <gtest/gtest.h>
21
22 #include "arrow/array.h"
23 // TODO ipc shouldn't be included here
24 #include "arrow/ipc/test_common.h"
25 #include "arrow/testing/gtest_util.h"
26 #include "arrow/testing/util.h"
27 #include "arrow/type.h"
28 #include "arrow/util/checked_cast.h"
29
30 namespace arrow {
31
32 using internal::checked_cast;
33
TEST(TestUnionArray,TestSliceEquals)34 TEST(TestUnionArray, TestSliceEquals) {
35 std::shared_ptr<RecordBatch> batch;
36 ASSERT_OK(ipc::test::MakeUnion(&batch));
37
38 auto CheckUnion = [](std::shared_ptr<Array> array) {
39 const int64_t size = array->length();
40 std::shared_ptr<Array> slice, slice2;
41 slice = array->Slice(2);
42 ASSERT_EQ(size - 2, slice->length());
43
44 slice2 = array->Slice(2);
45 ASSERT_EQ(size - 2, slice->length());
46
47 ASSERT_TRUE(slice->Equals(slice2));
48 ASSERT_TRUE(array->RangeEquals(2, array->length(), 0, slice));
49
50 // Chained slices
51 slice2 = array->Slice(1)->Slice(1);
52 ASSERT_TRUE(slice->Equals(slice2));
53
54 slice = array->Slice(1, 5);
55 slice2 = array->Slice(1, 5);
56 ASSERT_EQ(5, slice->length());
57
58 ASSERT_TRUE(slice->Equals(slice2));
59 ASSERT_TRUE(array->RangeEquals(1, 6, 0, slice));
60
61 AssertZeroPadded(*array);
62 TestInitialized(*array);
63 };
64
65 CheckUnion(batch->column(1));
66 CheckUnion(batch->column(2));
67 }
68
TEST(TestSparseUnionArray,Validate)69 TEST(TestSparseUnionArray, Validate) {
70 auto a = ArrayFromJSON(int32(), "[4, 5]");
71 auto type = union_({field("a", int32())}, UnionMode::SPARSE);
72 auto children = std::vector<std::shared_ptr<Array>>{a};
73 auto type_ids_array = ArrayFromJSON(int8(), "[0, 0, 0]");
74 auto type_ids = type_ids_array->data()->buffers[1];
75
76 auto arr = std::make_shared<UnionArray>(type, 2, children, type_ids);
77 ASSERT_OK(arr->ValidateFull());
78 arr = std::make_shared<UnionArray>(type, 1, children, type_ids, nullptr, nullptr, 0,
79 /*offset=*/1);
80 ASSERT_OK(arr->ValidateFull());
81 arr = std::make_shared<UnionArray>(type, 0, children, type_ids, nullptr, nullptr, 0,
82 /*offset=*/2);
83 ASSERT_OK(arr->ValidateFull());
84
85 // Length + offset < child length, but it's ok
86 arr = std::make_shared<UnionArray>(type, 1, children, type_ids, nullptr, nullptr, 0,
87 /*offset=*/0);
88 ASSERT_OK(arr->ValidateFull());
89
90 // Length + offset > child length
91 arr = std::make_shared<UnionArray>(type, 1, children, type_ids, nullptr, nullptr, 0,
92 /*offset=*/2);
93 ASSERT_RAISES(Invalid, arr->ValidateFull());
94
95 // Offset > child length
96 arr = std::make_shared<UnionArray>(type, 0, children, type_ids, nullptr, nullptr, 0,
97 /*offset=*/3);
98 ASSERT_RAISES(Invalid, arr->ValidateFull());
99 }
100
101 // -------------------------------------------------------------------------
102 // Tests for MakeDense and MakeSparse
103
104 class TestUnionArrayFactories : public ::testing::Test {
105 public:
SetUp()106 void SetUp() {
107 pool_ = default_memory_pool();
108 type_codes_ = {1, 2, 4, 8};
109 ArrayFromVector<Int8Type>({0, 1, 2, 0, 1, 3, 2, 0, 2, 1}, &type_ids_);
110 ArrayFromVector<Int8Type>({1, 2, 4, 1, 2, 8, 4, 1, 4, 2}, &logical_type_ids_);
111 ArrayFromVector<Int8Type>({1, 2, 4, 1, -2, 8, 4, 1, 4, 2}, &invalid_type_ids1_);
112 ArrayFromVector<Int8Type>({1, 2, 4, 1, 3, 8, 4, 1, 4, 2}, &invalid_type_ids2_);
113 }
114
CheckUnionArray(const UnionArray & array,UnionMode::type mode,const std::vector<std::string> & field_names,const std::vector<int8_t> & type_codes)115 void CheckUnionArray(const UnionArray& array, UnionMode::type mode,
116 const std::vector<std::string>& field_names,
117 const std::vector<int8_t>& type_codes) {
118 ASSERT_EQ(mode, array.mode());
119 CheckFieldNames(array, field_names);
120 CheckTypeCodes(array, type_codes);
121 const auto& type_ids = checked_cast<const Int8Array&>(*type_ids_);
122 for (int64_t i = 0; i < type_ids.length(); ++i) {
123 ASSERT_EQ(array.child_id(i), type_ids.Value(i));
124 }
125 ASSERT_EQ(nullptr, array.field(-1));
126 ASSERT_EQ(nullptr, array.field(static_cast<int>(type_ids.length())));
127 }
128
CheckFieldNames(const UnionArray & array,const std::vector<std::string> & names)129 void CheckFieldNames(const UnionArray& array, const std::vector<std::string>& names) {
130 const auto& type = checked_cast<const UnionType&>(*array.type());
131 ASSERT_EQ(type.num_fields(), names.size());
132 for (int i = 0; i < type.num_fields(); ++i) {
133 ASSERT_EQ(type.field(i)->name(), names[i]);
134 }
135 }
136
CheckTypeCodes(const UnionArray & array,const std::vector<int8_t> & codes)137 void CheckTypeCodes(const UnionArray& array, const std::vector<int8_t>& codes) {
138 const auto& type = checked_cast<const UnionType&>(*array.type());
139 ASSERT_EQ(codes, type.type_codes());
140 }
141
142 protected:
143 MemoryPool* pool_;
144 std::vector<int8_t> type_codes_;
145 std::shared_ptr<Array> type_ids_;
146 std::shared_ptr<Array> logical_type_ids_;
147 std::shared_ptr<Array> invalid_type_ids1_;
148 std::shared_ptr<Array> invalid_type_ids2_;
149 };
150
TEST_F(TestUnionArrayFactories,TestMakeDense)151 TEST_F(TestUnionArrayFactories, TestMakeDense) {
152 std::shared_ptr<Array> value_offsets;
153 ArrayFromVector<Int32Type, int32_t>({1, 0, 0, 0, 1, 0, 1, 2, 1, 2}, &value_offsets);
154
155 auto children = std::vector<std::shared_ptr<Array>>(4);
156 ArrayFromVector<StringType, std::string>({"abc", "def", "xyz"}, &children[0]);
157 ArrayFromVector<UInt8Type>({10, 20, 30}, &children[1]);
158 ArrayFromVector<DoubleType>({1.618, 2.718, 3.142}, &children[2]);
159 ArrayFromVector<Int8Type>({-12}, &children[3]);
160
161 std::vector<std::string> field_names = {"str", "int1", "real", "int2"};
162
163 std::shared_ptr<Array> result;
164 const UnionArray* union_array;
165
166 // without field names and type codes
167 ASSERT_OK_AND_ASSIGN(result,
168 UnionArray::MakeDense(*type_ids_, *value_offsets, children));
169 ASSERT_OK(result->ValidateFull());
170 union_array = checked_cast<const UnionArray*>(result.get());
171 CheckUnionArray(*union_array, UnionMode::DENSE, {"0", "1", "2", "3"}, {0, 1, 2, 3});
172
173 // with field name
174 ASSERT_RAISES(Invalid,
175 UnionArray::MakeDense(*type_ids_, *value_offsets, children, {"one"}));
176 ASSERT_OK_AND_ASSIGN(
177 result, UnionArray::MakeDense(*type_ids_, *value_offsets, children, field_names));
178 ASSERT_OK(result->ValidateFull());
179 union_array = checked_cast<const UnionArray*>(result.get());
180 CheckUnionArray(*union_array, UnionMode::DENSE, field_names, {0, 1, 2, 3});
181
182 // with type codes
183 ASSERT_RAISES(Invalid, UnionArray::MakeDense(*logical_type_ids_, *value_offsets,
184 children, std::vector<int8_t>{0}));
185 ASSERT_OK_AND_ASSIGN(result, UnionArray::MakeDense(*logical_type_ids_, *value_offsets,
186 children, type_codes_));
187 ASSERT_OK(result->ValidateFull());
188 union_array = checked_cast<const UnionArray*>(result.get());
189 CheckUnionArray(*union_array, UnionMode::DENSE, {"0", "1", "2", "3"}, type_codes_);
190
191 // with field names and type codes
192 ASSERT_RAISES(Invalid, UnionArray::MakeDense(*logical_type_ids_, *value_offsets,
193 children, {"one"}, type_codes_));
194 ASSERT_OK_AND_ASSIGN(result, UnionArray::MakeDense(*logical_type_ids_, *value_offsets,
195 children, field_names, type_codes_));
196 ASSERT_OK(result->ValidateFull());
197 union_array = checked_cast<const UnionArray*>(result.get());
198 CheckUnionArray(*union_array, UnionMode::DENSE, field_names, type_codes_);
199
200 // Invalid type codes
201 ASSERT_OK_AND_ASSIGN(result, UnionArray::MakeDense(*invalid_type_ids1_, *value_offsets,
202 children, type_codes_));
203 ASSERT_RAISES(Invalid, result->ValidateFull());
204 ASSERT_OK_AND_ASSIGN(result, UnionArray::MakeDense(*invalid_type_ids2_, *value_offsets,
205 children, type_codes_));
206 ASSERT_RAISES(Invalid, result->ValidateFull());
207
208 // Invalid offsets
209 std::shared_ptr<Array> invalid_offsets;
210 ArrayFromVector<Int32Type, int32_t>({1, 0, 0, 0, 1, 1, 1, 2, 1, 2}, &invalid_offsets);
211 ASSERT_OK_AND_ASSIGN(result,
212 UnionArray::MakeDense(*type_ids_, *invalid_offsets, children));
213 ASSERT_RAISES(Invalid, result->ValidateFull());
214 ArrayFromVector<Int32Type, int32_t>({1, 0, 0, 0, 1, -1, 1, 2, 1, 2}, &invalid_offsets);
215 ASSERT_OK_AND_ASSIGN(result,
216 UnionArray::MakeDense(*type_ids_, *invalid_offsets, children));
217 ASSERT_RAISES(Invalid, result->ValidateFull());
218 }
219
TEST_F(TestUnionArrayFactories,TestMakeSparse)220 TEST_F(TestUnionArrayFactories, TestMakeSparse) {
221 auto children = std::vector<std::shared_ptr<Array>>(4);
222 ArrayFromVector<StringType, std::string>(
223 {"abc", "", "", "def", "", "", "", "xyz", "", ""}, &children[0]);
224 ArrayFromVector<UInt8Type>({0, 10, 0, 0, 20, 0, 0, 0, 0, 30}, &children[1]);
225 ArrayFromVector<DoubleType>({0.0, 0.0, 1.618, 0.0, 0.0, 0.0, 2.718, 0.0, 3.142, 0.0},
226 &children[2]);
227 ArrayFromVector<Int8Type>({0, 0, 0, 0, 0, -12, 0, 0, 0, 0}, &children[3]);
228
229 std::vector<std::string> field_names = {"str", "int1", "real", "int2"};
230
231 std::shared_ptr<Array> result;
232
233 // without field names and type codes
234 ASSERT_OK_AND_ASSIGN(result, UnionArray::MakeSparse(*type_ids_, children));
235 ASSERT_OK(result->ValidateFull());
236 CheckUnionArray(checked_cast<UnionArray&>(*result), UnionMode::SPARSE,
237 {"0", "1", "2", "3"}, {0, 1, 2, 3});
238
239 // with field names
240 ASSERT_RAISES(Invalid, UnionArray::MakeSparse(*type_ids_, children, {"one"}));
241 ASSERT_OK_AND_ASSIGN(result, UnionArray::MakeSparse(*type_ids_, children, field_names));
242 ASSERT_OK(result->ValidateFull());
243 CheckUnionArray(checked_cast<UnionArray&>(*result), UnionMode::SPARSE, field_names,
244 {0, 1, 2, 3});
245
246 // with type codes
247 ASSERT_RAISES(Invalid, UnionArray::MakeSparse(*logical_type_ids_, children,
248 std::vector<int8_t>{0}));
249 ASSERT_OK_AND_ASSIGN(result,
250 UnionArray::MakeSparse(*logical_type_ids_, children, type_codes_));
251 ASSERT_OK(result->ValidateFull());
252 CheckUnionArray(checked_cast<UnionArray&>(*result), UnionMode::SPARSE,
253 {"0", "1", "2", "3"}, type_codes_);
254
255 // with field names and type codes
256 ASSERT_RAISES(Invalid, UnionArray::MakeSparse(*logical_type_ids_, children, {"one"},
257 type_codes_));
258 ASSERT_OK_AND_ASSIGN(result, UnionArray::MakeSparse(*logical_type_ids_, children,
259 field_names, type_codes_));
260 ASSERT_OK(result->ValidateFull());
261 CheckUnionArray(checked_cast<UnionArray&>(*result), UnionMode::SPARSE, field_names,
262 type_codes_);
263
264 // Invalid type codes
265 ASSERT_OK_AND_ASSIGN(
266 result, UnionArray::MakeSparse(*invalid_type_ids1_, children, type_codes_));
267 ASSERT_RAISES(Invalid, result->ValidateFull());
268 ASSERT_OK_AND_ASSIGN(
269 result, UnionArray::MakeSparse(*invalid_type_ids2_, children, type_codes_));
270 ASSERT_RAISES(Invalid, result->ValidateFull());
271
272 // Invalid child length
273 ArrayFromVector<Int8Type>({0, 0, 0, 0, 0, -12, 0, 0, 0}, &children[3]);
274 ASSERT_RAISES(Invalid, UnionArray::MakeSparse(*type_ids_, children));
275 }
276
277 template <typename B>
278 class UnionBuilderTest : public ::testing::Test {
279 public:
280 int8_t I8 = 8, STR = 13, DBL = 7;
281
AppendInt(int8_t i)282 virtual void AppendInt(int8_t i) {
283 expected_types_vector.push_back(I8);
284 ASSERT_OK(union_builder->Append(I8));
285 ASSERT_OK(i8_builder->Append(i));
286 }
287
AppendString(const std::string & str)288 virtual void AppendString(const std::string& str) {
289 expected_types_vector.push_back(STR);
290 ASSERT_OK(union_builder->Append(STR));
291 ASSERT_OK(str_builder->Append(str));
292 }
293
AppendDouble(double dbl)294 virtual void AppendDouble(double dbl) {
295 expected_types_vector.push_back(DBL);
296 ASSERT_OK(union_builder->Append(DBL));
297 ASSERT_OK(dbl_builder->Append(dbl));
298 }
299
AppendBasics()300 void AppendBasics() {
301 AppendInt(33);
302 AppendString("abc");
303 AppendDouble(1.0);
304 AppendDouble(-1.0);
305 AppendString("");
306 AppendInt(10);
307 AppendString("def");
308 AppendInt(-10);
309 AppendDouble(0.5);
310 ASSERT_OK(union_builder->Finish(&actual));
311 ArrayFromVector<Int8Type, uint8_t>(expected_types_vector, &expected_types);
312 }
313
AppendInferred()314 void AppendInferred() {
315 I8 = union_builder->AppendChild(i8_builder, "i8");
316 ASSERT_EQ(I8, 0);
317 AppendInt(33);
318 AppendInt(10);
319
320 STR = union_builder->AppendChild(str_builder, "str");
321 ASSERT_EQ(STR, 1);
322 AppendString("abc");
323 AppendString("");
324 AppendString("def");
325 AppendInt(-10);
326
327 DBL = union_builder->AppendChild(dbl_builder, "dbl");
328 ASSERT_EQ(DBL, 2);
329 AppendDouble(1.0);
330 AppendDouble(-1.0);
331 AppendDouble(0.5);
332 ASSERT_OK(union_builder->Finish(&actual));
333 ArrayFromVector<Int8Type, uint8_t>(expected_types_vector, &expected_types);
334
335 ASSERT_EQ(I8, 0);
336 ASSERT_EQ(STR, 1);
337 ASSERT_EQ(DBL, 2);
338 }
339
AppendListOfInferred(std::shared_ptr<ListArray> * actual)340 void AppendListOfInferred(std::shared_ptr<ListArray>* actual) {
341 ListBuilder list_builder(default_memory_pool(), union_builder);
342
343 ASSERT_OK(list_builder.Append());
344 I8 = union_builder->AppendChild(i8_builder, "i8");
345 ASSERT_EQ(I8, 0);
346 AppendInt(10);
347
348 ASSERT_OK(list_builder.Append());
349 STR = union_builder->AppendChild(str_builder, "str");
350 ASSERT_EQ(STR, 1);
351 AppendString("abc");
352 AppendInt(-10);
353
354 ASSERT_OK(list_builder.Append());
355 DBL = union_builder->AppendChild(dbl_builder, "dbl");
356 ASSERT_EQ(DBL, 2);
357 AppendDouble(0.5);
358
359 ASSERT_OK(list_builder.Finish(actual));
360 ArrayFromVector<Int8Type, uint8_t>(expected_types_vector, &expected_types);
361 }
362
363 std::vector<uint8_t> expected_types_vector;
364 std::shared_ptr<Array> expected_types;
365 std::shared_ptr<Int8Builder> i8_builder = std::make_shared<Int8Builder>();
366 std::shared_ptr<StringBuilder> str_builder = std::make_shared<StringBuilder>();
367 std::shared_ptr<DoubleBuilder> dbl_builder = std::make_shared<DoubleBuilder>();
368 std::shared_ptr<B> union_builder = std::make_shared<B>(default_memory_pool());
369 std::shared_ptr<UnionArray> actual;
370 };
371
372 class DenseUnionBuilderTest : public UnionBuilderTest<DenseUnionBuilder> {};
373 class SparseUnionBuilderTest : public UnionBuilderTest<SparseUnionBuilder> {
374 public:
375 using Base = UnionBuilderTest<SparseUnionBuilder>;
376
AppendInt(int8_t i)377 void AppendInt(int8_t i) override {
378 Base::AppendInt(i);
379 ASSERT_OK(str_builder->AppendNull());
380 ASSERT_OK(dbl_builder->AppendNull());
381 }
382
AppendString(const std::string & str)383 void AppendString(const std::string& str) override {
384 Base::AppendString(str);
385 ASSERT_OK(i8_builder->AppendNull());
386 ASSERT_OK(dbl_builder->AppendNull());
387 }
388
AppendDouble(double dbl)389 void AppendDouble(double dbl) override {
390 Base::AppendDouble(dbl);
391 ASSERT_OK(i8_builder->AppendNull());
392 ASSERT_OK(str_builder->AppendNull());
393 }
394 };
395
TEST_F(DenseUnionBuilderTest,Basics)396 TEST_F(DenseUnionBuilderTest, Basics) {
397 union_builder.reset(new DenseUnionBuilder(
398 default_memory_pool(), {i8_builder, str_builder, dbl_builder},
399 union_({field("i8", int8()), field("str", utf8()), field("dbl", float64())},
400 {I8, STR, DBL}, UnionMode::DENSE)));
401 AppendBasics();
402
403 auto expected_i8 = ArrayFromJSON(int8(), "[33, 10, -10]");
404 auto expected_str = ArrayFromJSON(utf8(), R"(["abc", "", "def"])");
405 auto expected_dbl = ArrayFromJSON(float64(), "[1.0, -1.0, 0.5]");
406
407 auto expected_offsets = ArrayFromJSON(int32(), "[0, 0, 0, 1, 1, 1, 2, 2, 2]");
408
409 ASSERT_OK_AND_ASSIGN(auto expected,
410 UnionArray::MakeDense(*expected_types, *expected_offsets,
411 {expected_i8, expected_str, expected_dbl},
412 {"i8", "str", "dbl"}, {I8, STR, DBL}));
413
414 ASSERT_EQ(expected->type()->ToString(), actual->type()->ToString());
415 ASSERT_ARRAYS_EQUAL(*expected, *actual);
416 }
417
TEST_F(DenseUnionBuilderTest,InferredType)418 TEST_F(DenseUnionBuilderTest, InferredType) {
419 AppendInferred();
420
421 auto expected_i8 = ArrayFromJSON(int8(), "[33, 10, -10]");
422 auto expected_str = ArrayFromJSON(utf8(), R"(["abc", "", "def"])");
423 auto expected_dbl = ArrayFromJSON(float64(), "[1.0, -1.0, 0.5]");
424
425 auto expected_offsets = ArrayFromJSON(int32(), "[0, 1, 0, 1, 2, 2, 0, 1, 2]");
426
427 ASSERT_OK_AND_ASSIGN(auto expected,
428 UnionArray::MakeDense(*expected_types, *expected_offsets,
429 {expected_i8, expected_str, expected_dbl},
430 {"i8", "str", "dbl"}, {I8, STR, DBL}));
431
432 ASSERT_EQ(expected->type()->ToString(), actual->type()->ToString());
433 ASSERT_ARRAYS_EQUAL(*expected, *actual);
434 }
435
TEST_F(DenseUnionBuilderTest,ListOfInferredType)436 TEST_F(DenseUnionBuilderTest, ListOfInferredType) {
437 std::shared_ptr<ListArray> actual;
438 AppendListOfInferred(&actual);
439
440 auto expected_type =
441 list(union_({field("i8", int8()), field("str", utf8()), field("dbl", float64())},
442 {I8, STR, DBL}, UnionMode::DENSE));
443 ASSERT_EQ(expected_type->ToString(), actual->type()->ToString());
444 }
445
TEST_F(SparseUnionBuilderTest,Basics)446 TEST_F(SparseUnionBuilderTest, Basics) {
447 union_builder.reset(new SparseUnionBuilder(
448 default_memory_pool(), {i8_builder, str_builder, dbl_builder},
449 union_({field("i8", int8()), field("str", utf8()), field("dbl", float64())},
450 {I8, STR, DBL}, UnionMode::SPARSE)));
451
452 AppendBasics();
453
454 auto expected_i8 =
455 ArrayFromJSON(int8(), "[33, null, null, null, null, 10, null, -10, null]");
456 auto expected_str =
457 ArrayFromJSON(utf8(), R"([null, "abc", null, null, "", null, "def", null, null])");
458 auto expected_dbl =
459 ArrayFromJSON(float64(), "[null, null, 1.0, -1.0, null, null, null, null, 0.5]");
460
461 ASSERT_OK_AND_ASSIGN(
462 auto expected,
463 UnionArray::MakeSparse(*expected_types, {expected_i8, expected_str, expected_dbl},
464 {"i8", "str", "dbl"}, {I8, STR, DBL}));
465
466 ASSERT_EQ(expected->type()->ToString(), actual->type()->ToString());
467 ASSERT_ARRAYS_EQUAL(*expected, *actual);
468 }
469
TEST_F(SparseUnionBuilderTest,InferredType)470 TEST_F(SparseUnionBuilderTest, InferredType) {
471 AppendInferred();
472
473 auto expected_i8 =
474 ArrayFromJSON(int8(), "[33, 10, null, null, null, -10, null, null, null]");
475 auto expected_str =
476 ArrayFromJSON(utf8(), R"([null, null, "abc", "", "def", null, null, null, null])");
477 auto expected_dbl =
478 ArrayFromJSON(float64(), "[null, null, null, null, null, null, 1.0, -1.0, 0.5]");
479
480 ASSERT_OK_AND_ASSIGN(
481 auto expected,
482 UnionArray::MakeSparse(*expected_types, {expected_i8, expected_str, expected_dbl},
483 {"i8", "str", "dbl"}, {I8, STR, DBL}));
484
485 ASSERT_EQ(expected->type()->ToString(), actual->type()->ToString());
486 ASSERT_ARRAYS_EQUAL(*expected, *actual);
487 }
488
TEST_F(SparseUnionBuilderTest,StructWithUnion)489 TEST_F(SparseUnionBuilderTest, StructWithUnion) {
490 auto union_builder = std::make_shared<SparseUnionBuilder>(default_memory_pool());
491 StructBuilder builder(struct_({field("u", union_builder->type())}),
492 default_memory_pool(), {union_builder});
493 ASSERT_EQ(union_builder->AppendChild(std::make_shared<Int32Builder>(), "i"), 0);
494 ASSERT_TRUE(
495 builder.type()->Equals(struct_({field("u", union_({field("i", int32())}, {0}))})));
496 }
497
498 } // namespace arrow
499