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