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 <cstdint>
19 #include <memory>
20 #include <vector>
21 
22 #include <gmock/gmock.h>
23 #include <gtest/gtest.h>
24 
25 #include "arrow/array.h"
26 #include "arrow/record_batch.h"
27 #include "arrow/status.h"
28 #include "arrow/table.h"
29 #include "arrow/testing/gtest_common.h"
30 #include "arrow/testing/gtest_util.h"
31 #include "arrow/testing/random.h"
32 #include "arrow/testing/util.h"
33 #include "arrow/type.h"
34 #include "arrow/util/key_value_metadata.h"
35 
36 namespace arrow {
37 
38 class TestChunkedArray : public TestBase {
39  protected:
Construct()40   virtual void Construct() {
41     one_ = std::make_shared<ChunkedArray>(arrays_one_);
42     if (!arrays_another_.empty()) {
43       another_ = std::make_shared<ChunkedArray>(arrays_another_);
44     }
45   }
46 
47   ArrayVector arrays_one_;
48   ArrayVector arrays_another_;
49 
50   std::shared_ptr<ChunkedArray> one_;
51   std::shared_ptr<ChunkedArray> another_;
52 };
53 
TEST_F(TestChunkedArray,BasicEquals)54 TEST_F(TestChunkedArray, BasicEquals) {
55   std::vector<bool> null_bitmap(100, true);
56   std::vector<int32_t> data(100, 1);
57   std::shared_ptr<Array> array;
58   ArrayFromVector<Int32Type, int32_t>(null_bitmap, data, &array);
59   arrays_one_.push_back(array);
60   arrays_another_.push_back(array);
61 
62   Construct();
63   ASSERT_TRUE(one_->Equals(one_));
64   ASSERT_FALSE(one_->Equals(nullptr));
65   ASSERT_TRUE(one_->Equals(another_));
66   ASSERT_TRUE(one_->Equals(*another_.get()));
67 }
68 
TEST_F(TestChunkedArray,EqualsDifferingTypes)69 TEST_F(TestChunkedArray, EqualsDifferingTypes) {
70   std::vector<bool> null_bitmap(100, true);
71   std::vector<int32_t> data32(100, 1);
72   std::vector<int64_t> data64(100, 1);
73   std::shared_ptr<Array> array;
74   ArrayFromVector<Int32Type, int32_t>(null_bitmap, data32, &array);
75   arrays_one_.push_back(array);
76   ArrayFromVector<Int64Type, int64_t>(null_bitmap, data64, &array);
77   arrays_another_.push_back(array);
78 
79   Construct();
80   ASSERT_FALSE(one_->Equals(another_));
81   ASSERT_FALSE(one_->Equals(*another_.get()));
82 }
83 
TEST_F(TestChunkedArray,EqualsDifferingLengths)84 TEST_F(TestChunkedArray, EqualsDifferingLengths) {
85   std::vector<bool> null_bitmap100(100, true);
86   std::vector<bool> null_bitmap101(101, true);
87   std::vector<int32_t> data100(100, 1);
88   std::vector<int32_t> data101(101, 1);
89   std::shared_ptr<Array> array;
90   ArrayFromVector<Int32Type, int32_t>(null_bitmap100, data100, &array);
91   arrays_one_.push_back(array);
92   ArrayFromVector<Int32Type, int32_t>(null_bitmap101, data101, &array);
93   arrays_another_.push_back(array);
94 
95   Construct();
96   ASSERT_FALSE(one_->Equals(another_));
97   ASSERT_FALSE(one_->Equals(*another_.get()));
98 
99   std::vector<bool> null_bitmap1(1, true);
100   std::vector<int32_t> data1(1, 1);
101   ArrayFromVector<Int32Type, int32_t>(null_bitmap1, data1, &array);
102   arrays_one_.push_back(array);
103 
104   Construct();
105   ASSERT_TRUE(one_->Equals(another_));
106   ASSERT_TRUE(one_->Equals(*another_.get()));
107 }
108 
TEST_F(TestChunkedArray,EqualsDifferingMetadata)109 TEST_F(TestChunkedArray, EqualsDifferingMetadata) {
110   auto left_ty = list(field("item", int32()));
111 
112   auto metadata = key_value_metadata({"foo"}, {"bar"});
113   auto right_ty = list(field("item", int32(), true, metadata));
114 
115   std::vector<std::shared_ptr<Array>> left_chunks = {ArrayFromJSON(left_ty, "[[]]")};
116   std::vector<std::shared_ptr<Array>> right_chunks = {ArrayFromJSON(right_ty, "[[]]")};
117 
118   ChunkedArray left(left_chunks);
119   ChunkedArray right(right_chunks);
120   ASSERT_TRUE(left.Equals(right));
121 }
122 
TEST_F(TestChunkedArray,SliceEquals)123 TEST_F(TestChunkedArray, SliceEquals) {
124   arrays_one_.push_back(MakeRandomArray<Int32Array>(100));
125   arrays_one_.push_back(MakeRandomArray<Int32Array>(50));
126   arrays_one_.push_back(MakeRandomArray<Int32Array>(50));
127   Construct();
128 
129   std::shared_ptr<ChunkedArray> slice = one_->Slice(125, 50);
130   ASSERT_EQ(slice->length(), 50);
131   AssertChunkedEqual(*one_->Slice(125, 50), *slice);
132 
133   std::shared_ptr<ChunkedArray> slice2 = one_->Slice(75)->Slice(25)->Slice(25, 50);
134   ASSERT_EQ(slice2->length(), 50);
135   AssertChunkedEqual(*slice, *slice2);
136 
137   // Making empty slices of a ChunkedArray
138   std::shared_ptr<ChunkedArray> slice3 = one_->Slice(one_->length(), 99);
139   ASSERT_EQ(slice3->length(), 0);
140   ASSERT_EQ(slice3->num_chunks(), 1);
141   ASSERT_TRUE(slice3->type()->Equals(one_->type()));
142 
143   std::shared_ptr<ChunkedArray> slice4 = one_->Slice(10, 0);
144   ASSERT_EQ(slice4->length(), 0);
145   ASSERT_EQ(slice4->num_chunks(), 1);
146   ASSERT_TRUE(slice4->type()->Equals(one_->type()));
147 
148   // Slicing an empty ChunkedArray
149   std::shared_ptr<ChunkedArray> slice5 = slice4->Slice(0, 10);
150   ASSERT_EQ(slice5->length(), 0);
151   ASSERT_EQ(slice5->num_chunks(), 1);
152   ASSERT_TRUE(slice5->type()->Equals(one_->type()));
153 }
154 
TEST_F(TestChunkedArray,ZeroChunksIssues)155 TEST_F(TestChunkedArray, ZeroChunksIssues) {
156   ArrayVector empty = {};
157   auto no_chunks = std::make_shared<ChunkedArray>(empty, int8());
158 
159   // ARROW-8911, assert that slicing is a no-op when there are zero-chunks
160   auto sliced = no_chunks->Slice(0, 0);
161   auto sliced2 = no_chunks->Slice(0, 5);
162   AssertChunkedEqual(*no_chunks, *sliced);
163   AssertChunkedEqual(*no_chunks, *sliced2);
164 }
165 
TEST_F(TestChunkedArray,Validate)166 TEST_F(TestChunkedArray, Validate) {
167   // Valid if empty
168   ArrayVector empty = {};
169   auto no_chunks = std::make_shared<ChunkedArray>(empty, utf8());
170   ASSERT_OK(no_chunks->ValidateFull());
171 
172   random::RandomArrayGenerator gen(0);
173   arrays_one_.push_back(gen.Int32(50, 0, 100, 0.1));
174   Construct();
175   ASSERT_OK(one_->ValidateFull());
176 
177   arrays_one_.push_back(gen.Int32(50, 0, 100, 0.1));
178   Construct();
179   ASSERT_OK(one_->ValidateFull());
180 
181   arrays_one_.push_back(gen.String(50, 0, 10, 0.1));
182   Construct();
183   ASSERT_RAISES(Invalid, one_->ValidateFull());
184 }
185 
TEST_F(TestChunkedArray,View)186 TEST_F(TestChunkedArray, View) {
187   auto in_ty = int32();
188   auto out_ty = fixed_size_binary(4);
189 #if ARROW_LITTLE_ENDIAN
190   auto arr = ArrayFromJSON(in_ty, "[2020568934, 2054316386, null]");
191   auto arr2 = ArrayFromJSON(in_ty, "[2020568934, 2054316386]");
192 #else
193   auto arr = ArrayFromJSON(in_ty, "[1718579064, 1650553466, null]");
194   auto arr2 = ArrayFromJSON(in_ty, "[1718579064, 1650553466]");
195 #endif
196   auto ex = ArrayFromJSON(out_ty, R"(["foox", "barz", null])");
197   auto ex2 = ArrayFromJSON(out_ty, R"(["foox", "barz"])");
198 
199   ArrayVector chunks = {arr, arr2};
200   ArrayVector ex_chunks = {ex, ex2};
201   auto carr = std::make_shared<ChunkedArray>(chunks);
202   auto expected = std::make_shared<ChunkedArray>(ex_chunks);
203 
204   ASSERT_OK_AND_ASSIGN(auto result, carr->View(out_ty));
205   AssertChunkedEqual(*expected, *result);
206 
207   // Zero length
208   ArrayVector empty = {};
209   carr = std::make_shared<ChunkedArray>(empty, in_ty);
210   expected = std::make_shared<ChunkedArray>(empty, out_ty);
211   ASSERT_OK_AND_ASSIGN(result, carr->View(out_ty));
212   AssertChunkedEqual(*expected, *result);
213 }
214 
215 class TestTable : public TestBase {
216  public:
MakeExample1(int length)217   void MakeExample1(int length) {
218     auto f0 = field("f0", int32());
219     auto f1 = field("f1", uint8());
220     auto f2 = field("f2", int16());
221 
222     std::vector<std::shared_ptr<Field>> fields = {f0, f1, f2};
223     schema_ = std::make_shared<Schema>(fields);
224 
225     arrays_ = {MakeRandomArray<Int32Array>(length), MakeRandomArray<UInt8Array>(length),
226                MakeRandomArray<Int16Array>(length)};
227 
228     columns_ = {std::make_shared<ChunkedArray>(arrays_[0]),
229                 std::make_shared<ChunkedArray>(arrays_[1]),
230                 std::make_shared<ChunkedArray>(arrays_[2])};
231   }
232 
233  protected:
234   std::shared_ptr<Table> table_;
235   std::shared_ptr<Schema> schema_;
236 
237   std::vector<std::shared_ptr<Array>> arrays_;
238   std::vector<std::shared_ptr<ChunkedArray>> columns_;
239 };
240 
TEST_F(TestTable,EmptySchema)241 TEST_F(TestTable, EmptySchema) {
242   auto empty_schema = ::arrow::schema({});
243   table_ = Table::Make(empty_schema, columns_);
244   ASSERT_OK(table_->ValidateFull());
245   ASSERT_EQ(0, table_->num_rows());
246   ASSERT_EQ(0, table_->num_columns());
247 }
248 
TEST_F(TestTable,Ctors)249 TEST_F(TestTable, Ctors) {
250   const int length = 100;
251   MakeExample1(length);
252 
253   table_ = Table::Make(schema_, columns_);
254   ASSERT_OK(table_->ValidateFull());
255   ASSERT_EQ(length, table_->num_rows());
256   ASSERT_EQ(3, table_->num_columns());
257 
258   auto array_ctor = Table::Make(schema_, arrays_);
259   ASSERT_TRUE(table_->Equals(*array_ctor));
260 
261   table_ = Table::Make(schema_, columns_, length);
262   ASSERT_OK(table_->ValidateFull());
263   ASSERT_EQ(length, table_->num_rows());
264 
265   table_ = Table::Make(schema_, arrays_);
266   ASSERT_OK(table_->ValidateFull());
267   ASSERT_EQ(length, table_->num_rows());
268   ASSERT_EQ(3, table_->num_columns());
269 }
270 
TEST_F(TestTable,Metadata)271 TEST_F(TestTable, Metadata) {
272   const int length = 100;
273   MakeExample1(length);
274 
275   table_ = Table::Make(schema_, columns_);
276 
277   ASSERT_TRUE(table_->schema()->Equals(*schema_));
278 
279   auto col = table_->column(0);
280   ASSERT_EQ(schema_->field(0)->type(), col->type());
281 }
282 
TEST_F(TestTable,InvalidColumns)283 TEST_F(TestTable, InvalidColumns) {
284   // Check that columns are all the same length
285   const int length = 100;
286   MakeExample1(length);
287 
288   table_ = Table::Make(schema_, columns_, length - 1);
289   ASSERT_RAISES(Invalid, table_->ValidateFull());
290 
291   columns_.clear();
292 
293   // Wrong number of columns
294   table_ = Table::Make(schema_, columns_, length);
295   ASSERT_RAISES(Invalid, table_->ValidateFull());
296 
297   columns_ = {std::make_shared<ChunkedArray>(MakeRandomArray<Int32Array>(length)),
298               std::make_shared<ChunkedArray>(MakeRandomArray<UInt8Array>(length)),
299               std::make_shared<ChunkedArray>(MakeRandomArray<Int16Array>(length - 1))};
300 
301   table_ = Table::Make(schema_, columns_, length);
302   ASSERT_RAISES(Invalid, table_->ValidateFull());
303 }
304 
TEST_F(TestTable,AllColumnsAndFields)305 TEST_F(TestTable, AllColumnsAndFields) {
306   const int length = 100;
307   MakeExample1(length);
308   table_ = Table::Make(schema_, columns_);
309 
310   auto columns = table_->columns();
311   auto fields = table_->fields();
312 
313   for (int i = 0; i < table_->num_columns(); ++i) {
314     AssertChunkedEqual(*table_->column(i), *columns[i]);
315     AssertFieldEqual(*table_->field(i), *fields[i]);
316   }
317 
318   // Zero length
319   std::vector<std::shared_ptr<Array>> t2_columns;
320   auto t2 = Table::Make(::arrow::schema({}), t2_columns);
321   columns = t2->columns();
322   fields = t2->fields();
323 
324   ASSERT_EQ(0, columns.size());
325   ASSERT_EQ(0, fields.size());
326 }
327 
TEST_F(TestTable,Equals)328 TEST_F(TestTable, Equals) {
329   const int length = 100;
330   MakeExample1(length);
331 
332   table_ = Table::Make(schema_, columns_);
333 
334   ASSERT_TRUE(table_->Equals(*table_));
335   // Differing schema
336   auto f0 = field("f3", int32());
337   auto f1 = field("f4", uint8());
338   auto f2 = field("f5", int16());
339   std::vector<std::shared_ptr<Field>> fields = {f0, f1, f2};
340   auto other_schema = std::make_shared<Schema>(fields);
341   auto other = Table::Make(other_schema, columns_);
342   ASSERT_FALSE(table_->Equals(*other));
343   // Differing columns
344   std::vector<std::shared_ptr<ChunkedArray>> other_columns = {
345       std::make_shared<ChunkedArray>(MakeRandomArray<Int32Array>(length, 10)),
346       std::make_shared<ChunkedArray>(MakeRandomArray<UInt8Array>(length, 10)),
347       std::make_shared<ChunkedArray>(MakeRandomArray<Int16Array>(length, 10))};
348 
349   other = Table::Make(schema_, other_columns);
350   ASSERT_FALSE(table_->Equals(*other));
351 
352   // Differring schema metadata
353   other_schema = schema_->WithMetadata(::arrow::key_value_metadata({"key"}, {"value"}));
354   other = Table::Make(other_schema, columns_);
355   ASSERT_TRUE(table_->Equals(*other));
356   ASSERT_FALSE(table_->Equals(*other, /*check_metadata=*/true));
357 }
358 
TEST_F(TestTable,FromRecordBatches)359 TEST_F(TestTable, FromRecordBatches) {
360   const int64_t length = 10;
361   MakeExample1(length);
362 
363   auto batch1 = RecordBatch::Make(schema_, length, arrays_);
364 
365   ASSERT_OK_AND_ASSIGN(auto result, Table::FromRecordBatches({batch1}));
366 
367   auto expected = Table::Make(schema_, columns_);
368   ASSERT_TRUE(result->Equals(*expected));
369 
370   std::vector<std::shared_ptr<ChunkedArray>> other_columns;
371   for (int i = 0; i < schema_->num_fields(); ++i) {
372     std::vector<std::shared_ptr<Array>> col_arrays = {arrays_[i], arrays_[i]};
373     other_columns.push_back(std::make_shared<ChunkedArray>(col_arrays));
374   }
375 
376   ASSERT_OK_AND_ASSIGN(result, Table::FromRecordBatches({batch1, batch1}));
377   expected = Table::Make(schema_, other_columns);
378   ASSERT_TRUE(result->Equals(*expected));
379 
380   // Error states
381   std::vector<std::shared_ptr<RecordBatch>> empty_batches;
382   ASSERT_RAISES(Invalid, Table::FromRecordBatches(empty_batches));
383 
384   auto other_schema = ::arrow::schema({schema_->field(0), schema_->field(1)});
385 
386   std::vector<std::shared_ptr<Array>> other_arrays = {arrays_[0], arrays_[1]};
387   auto batch2 = RecordBatch::Make(other_schema, length, other_arrays);
388   ASSERT_RAISES(Invalid, Table::FromRecordBatches({batch1, batch2}));
389 }
390 
TEST_F(TestTable,FromRecordBatchesZeroLength)391 TEST_F(TestTable, FromRecordBatchesZeroLength) {
392   // ARROW-2307
393   MakeExample1(10);
394 
395   ASSERT_OK_AND_ASSIGN(auto result, Table::FromRecordBatches(schema_, {}));
396 
397   ASSERT_EQ(0, result->num_rows());
398   ASSERT_TRUE(result->schema()->Equals(*schema_));
399 }
400 
TEST_F(TestTable,CombineChunksEmptyTable)401 TEST_F(TestTable, CombineChunksEmptyTable) {
402   MakeExample1(10);
403 
404   ASSERT_OK_AND_ASSIGN(auto table, Table::FromRecordBatches(schema_, {}));
405   ASSERT_EQ(0, table->num_rows());
406 
407   ASSERT_OK_AND_ASSIGN(auto compacted, table->CombineChunks());
408 
409   EXPECT_TRUE(compacted->Equals(*table));
410 }
411 
TEST_F(TestTable,CombineChunks)412 TEST_F(TestTable, CombineChunks) {
413   MakeExample1(10);
414   auto batch1 = RecordBatch::Make(schema_, 10, arrays_);
415 
416   MakeExample1(15);
417   auto batch2 = RecordBatch::Make(schema_, 15, arrays_);
418 
419   ASSERT_OK_AND_ASSIGN(auto table, Table::FromRecordBatches({batch1, batch2}));
420   for (int i = 0; i < table->num_columns(); ++i) {
421     ASSERT_EQ(2, table->column(i)->num_chunks());
422   }
423 
424   ASSERT_OK_AND_ASSIGN(auto compacted, table->CombineChunks());
425 
426   EXPECT_TRUE(compacted->Equals(*table));
427   for (int i = 0; i < compacted->num_columns(); ++i) {
428     EXPECT_EQ(1, compacted->column(i)->num_chunks());
429   }
430 }
431 
TEST_F(TestTable,ConcatenateTables)432 TEST_F(TestTable, ConcatenateTables) {
433   const int64_t length = 10;
434 
435   MakeExample1(length);
436   auto batch1 = RecordBatch::Make(schema_, length, arrays_);
437 
438   // generate different data
439   MakeExample1(length);
440   auto batch2 = RecordBatch::Make(schema_, length, arrays_);
441 
442   ASSERT_OK_AND_ASSIGN(auto t1, Table::FromRecordBatches({batch1}));
443   ASSERT_OK_AND_ASSIGN(auto t2, Table::FromRecordBatches({batch2}));
444 
445   ASSERT_OK_AND_ASSIGN(auto result, ConcatenateTables({t1, t2}));
446   ASSERT_OK_AND_ASSIGN(auto expected, Table::FromRecordBatches({batch1, batch2}));
447   AssertTablesEqual(*expected, *result);
448 
449   // Error states
450   std::vector<std::shared_ptr<Table>> empty_tables;
451   ASSERT_RAISES(Invalid, ConcatenateTables(empty_tables));
452 
453   auto other_schema = ::arrow::schema({schema_->field(0), schema_->field(1)});
454 
455   std::vector<std::shared_ptr<Array>> other_arrays = {arrays_[0], arrays_[1]};
456   auto batch3 = RecordBatch::Make(other_schema, length, other_arrays);
457   ASSERT_OK_AND_ASSIGN(auto t3, Table::FromRecordBatches({batch3}));
458 
459   ASSERT_RAISES(Invalid, ConcatenateTables({t1, t3}));
460 }
461 
MakeTableWithOneNullFilledColumn(const std::string & column_name,const std::shared_ptr<DataType> & data_type,const int length)462 std::shared_ptr<Table> MakeTableWithOneNullFilledColumn(
463     const std::string& column_name, const std::shared_ptr<DataType>& data_type,
464     const int length) {
465   auto array_of_nulls = *MakeArrayOfNull(data_type, length);
466   return Table::Make(schema({field(column_name, data_type)}), {array_of_nulls});
467 }
468 
469 using TestPromoteTableToSchema = TestTable;
470 
TEST_F(TestPromoteTableToSchema,IdenticalSchema)471 TEST_F(TestPromoteTableToSchema, IdenticalSchema) {
472   const int length = 10;
473   auto metadata =
474       std::shared_ptr<KeyValueMetadata>(new KeyValueMetadata({"foo"}, {"bar"}));
475   MakeExample1(length);
476   std::shared_ptr<Table> table = Table::Make(schema_, arrays_);
477 
478   ASSERT_OK_AND_ASSIGN(auto result,
479                        PromoteTableToSchema(table, schema_->WithMetadata(metadata)));
480 
481   std::shared_ptr<Table> expected = table->ReplaceSchemaMetadata(metadata);
482 
483   ASSERT_TRUE(result->Equals(*expected));
484 }
485 
486 // The promoted table's fields are ordered the same as the promote-to schema.
TEST_F(TestPromoteTableToSchema,FieldsReorderedAfterPromotion)487 TEST_F(TestPromoteTableToSchema, FieldsReorderedAfterPromotion) {
488   const int length = 10;
489   MakeExample1(length);
490 
491   std::vector<std::shared_ptr<Field>> reversed_fields(schema_->fields().crbegin(),
492                                                       schema_->fields().crend());
493   std::vector<std::shared_ptr<Array>> reversed_arrays(arrays_.crbegin(), arrays_.crend());
494 
495   std::shared_ptr<Table> table = Table::Make(schema(reversed_fields), reversed_arrays);
496 
497   ASSERT_OK_AND_ASSIGN(auto result, PromoteTableToSchema(table, schema_));
498 
499   ASSERT_TRUE(result->schema()->Equals(*schema_));
500 }
501 
TEST_F(TestPromoteTableToSchema,PromoteNullTypeField)502 TEST_F(TestPromoteTableToSchema, PromoteNullTypeField) {
503   const int length = 10;
504   auto metadata =
505       std::shared_ptr<KeyValueMetadata>(new KeyValueMetadata({"foo"}, {"bar"}));
506   auto table_with_null_column = MakeTableWithOneNullFilledColumn("field", null(), length)
507                                     ->ReplaceSchemaMetadata(metadata);
508   auto promoted_schema = schema({field("field", int32())});
509 
510   ASSERT_OK_AND_ASSIGN(auto result,
511                        PromoteTableToSchema(table_with_null_column, promoted_schema));
512 
513   ASSERT_TRUE(
514       result->Equals(*MakeTableWithOneNullFilledColumn("field", int32(), length)));
515 }
516 
TEST_F(TestPromoteTableToSchema,AddMissingField)517 TEST_F(TestPromoteTableToSchema, AddMissingField) {
518   const int length = 10;
519   auto f0 = field("f0", int32());
520   auto table = Table::Make(schema({}), std::vector<std::shared_ptr<Array>>(), length);
521   auto promoted_schema = schema({field("field", int32())});
522 
523   ASSERT_OK_AND_ASSIGN(auto result, PromoteTableToSchema(table, promoted_schema));
524 
525   ASSERT_TRUE(
526       result->Equals(*MakeTableWithOneNullFilledColumn("field", int32(), length)));
527 }
528 
TEST_F(TestPromoteTableToSchema,IncompatibleTypes)529 TEST_F(TestPromoteTableToSchema, IncompatibleTypes) {
530   const int length = 10;
531   auto table = MakeTableWithOneNullFilledColumn("field", int32(), length);
532 
533   // Invalid promotion: int32 to null.
534   ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("field", null())})));
535 
536   // Invalid promotion: int32 to uint32.
537   ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("field", uint32())})));
538 }
539 
TEST_F(TestPromoteTableToSchema,IncompatibleNullity)540 TEST_F(TestPromoteTableToSchema, IncompatibleNullity) {
541   const int length = 10;
542   auto table = MakeTableWithOneNullFilledColumn("field", int32(), length);
543   ASSERT_RAISES(Invalid,
544                 PromoteTableToSchema(
545                     table, schema({field("field", uint32())->WithNullable(false)})));
546 }
547 
TEST_F(TestPromoteTableToSchema,DuplicateFieldNames)548 TEST_F(TestPromoteTableToSchema, DuplicateFieldNames) {
549   const int length = 10;
550 
551   auto table = Table::Make(
552       schema({field("field", int32()), field("field", null())}),
553       {MakeRandomArray<Int32Array>(length), MakeRandomArray<NullArray>(length)});
554 
555   ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("field", int32())})));
556 }
557 
TEST_F(TestPromoteTableToSchema,TableFieldAbsentFromSchema)558 TEST_F(TestPromoteTableToSchema, TableFieldAbsentFromSchema) {
559   const int length = 10;
560 
561   auto table =
562       Table::Make(schema({field("f0", int32())}), {MakeRandomArray<Int32Array>(length)});
563 
564   std::shared_ptr<Table> result;
565   ASSERT_RAISES(Invalid, PromoteTableToSchema(table, schema({field("f1", int32())})));
566 }
567 
568 class ConcatenateTablesWithPromotionTest : public TestTable {
569  protected:
GetOptions()570   ConcatenateTablesOptions GetOptions() {
571     ConcatenateTablesOptions options;
572     options.unify_schemas = true;
573     return options;
574   }
575 
MakeExample2(int length)576   void MakeExample2(int length) {
577     auto f0 = field("f0", int32());
578     auto f1 = field("f1", null());
579 
580     std::vector<std::shared_ptr<Field>> fields = {f0, f1};
581     schema_ = std::make_shared<Schema>(fields);
582 
583     arrays_ = {MakeRandomArray<Int32Array>(length), MakeRandomArray<NullArray>(length)};
584 
585     columns_ = {std::make_shared<ChunkedArray>(arrays_[0]),
586                 std::make_shared<ChunkedArray>(arrays_[1])};
587   }
588 
AssertTablesEqualUnorderedFields(const Table & lhs,const Table & rhs)589   void AssertTablesEqualUnorderedFields(const Table& lhs, const Table& rhs) {
590     ASSERT_EQ(lhs.schema()->num_fields(), rhs.schema()->num_fields());
591     if (lhs.schema()->metadata()) {
592       ASSERT_NE(nullptr, rhs.schema()->metadata());
593       ASSERT_TRUE(lhs.schema()->metadata()->Equals(*rhs.schema()->metadata()));
594     } else {
595       ASSERT_EQ(nullptr, rhs.schema()->metadata());
596     }
597     for (int i = 0; i < lhs.schema()->num_fields(); ++i) {
598       const auto& lhs_field = lhs.schema()->field(i);
599       const auto& rhs_field = rhs.schema()->GetFieldByName(lhs_field->name());
600       ASSERT_NE(nullptr, rhs_field);
601       ASSERT_TRUE(lhs_field->Equals(rhs_field, true));
602       const auto& lhs_column = lhs.column(i);
603       const auto& rhs_column = rhs.GetColumnByName(lhs_field->name());
604       AssertChunkedEqual(*lhs_column, *rhs_column);
605     }
606   }
607 };
608 
TEST_F(ConcatenateTablesWithPromotionTest,Simple)609 TEST_F(ConcatenateTablesWithPromotionTest, Simple) {
610   const int64_t length = 10;
611 
612   MakeExample1(length);
613   auto batch1 = RecordBatch::Make(schema_, length, arrays_);
614 
615   ASSERT_OK_AND_ASSIGN(auto f1_nulls, MakeArrayOfNull(schema_->field(1)->type(), length));
616   ASSERT_OK_AND_ASSIGN(auto f2_nulls, MakeArrayOfNull(schema_->field(2)->type(), length));
617 
618   MakeExample2(length);
619   auto batch2 = RecordBatch::Make(schema_, length, arrays_);
620 
621   auto batch2_null_filled =
622       RecordBatch::Make(batch1->schema(), length, {arrays_[0], f1_nulls, f2_nulls});
623 
624   ASSERT_OK_AND_ASSIGN(auto t1, Table::FromRecordBatches({batch1}));
625   ASSERT_OK_AND_ASSIGN(auto t2, Table::FromRecordBatches({batch2}));
626   ASSERT_OK_AND_ASSIGN(auto t3, Table::FromRecordBatches({batch2_null_filled}));
627 
628   ASSERT_OK_AND_ASSIGN(auto result, ConcatenateTables({t1, t2}, GetOptions()));
629   ASSERT_OK_AND_ASSIGN(auto expected, ConcatenateTables({t1, t3}));
630   AssertTablesEqualUnorderedFields(*expected, *result);
631 
632   ASSERT_OK_AND_ASSIGN(result, ConcatenateTables({t2, t1}, GetOptions()));
633   ASSERT_OK_AND_ASSIGN(expected, ConcatenateTables({t3, t1}));
634   AssertTablesEqualUnorderedFields(*expected, *result);
635 }
636 
TEST_F(TestTable,Slice)637 TEST_F(TestTable, Slice) {
638   const int64_t length = 10;
639 
640   MakeExample1(length);
641   auto batch = RecordBatch::Make(schema_, length, arrays_);
642 
643   ASSERT_OK_AND_ASSIGN(auto half, Table::FromRecordBatches({batch}));
644   ASSERT_OK_AND_ASSIGN(auto whole, Table::FromRecordBatches({batch, batch}));
645   ASSERT_OK_AND_ASSIGN(auto three, Table::FromRecordBatches({batch, batch, batch}));
646 
647   AssertTablesEqual(*whole->Slice(0, length), *half);
648   AssertTablesEqual(*whole->Slice(length), *half);
649   AssertTablesEqual(*whole->Slice(length / 3, 2 * (length - length / 3)),
650                     *three->Slice(length + length / 3, 2 * (length - length / 3)));
651 }
652 
TEST_F(TestTable,RemoveColumn)653 TEST_F(TestTable, RemoveColumn) {
654   const int64_t length = 10;
655   MakeExample1(length);
656 
657   auto table_sp = Table::Make(schema_, columns_);
658   const Table& table = *table_sp;
659 
660   ASSERT_OK_AND_ASSIGN(auto result, table.RemoveColumn(0));
661 
662   auto ex_schema = ::arrow::schema({schema_->field(1), schema_->field(2)});
663   std::vector<std::shared_ptr<ChunkedArray>> ex_columns = {table.column(1),
664                                                            table.column(2)};
665 
666   auto expected = Table::Make(ex_schema, ex_columns);
667   ASSERT_TRUE(result->Equals(*expected));
668 
669   ASSERT_OK_AND_ASSIGN(result, table.RemoveColumn(1));
670   ex_schema = ::arrow::schema({schema_->field(0), schema_->field(2)});
671   ex_columns = {table.column(0), table.column(2)};
672 
673   expected = Table::Make(ex_schema, ex_columns);
674   ASSERT_TRUE(result->Equals(*expected));
675 
676   ASSERT_OK_AND_ASSIGN(result, table.RemoveColumn(2));
677   ex_schema = ::arrow::schema({schema_->field(0), schema_->field(1)});
678   ex_columns = {table.column(0), table.column(1)};
679   expected = Table::Make(ex_schema, ex_columns);
680   ASSERT_TRUE(result->Equals(*expected));
681 }
682 
TEST_F(TestTable,SetColumn)683 TEST_F(TestTable, SetColumn) {
684   const int64_t length = 10;
685   MakeExample1(length);
686 
687   auto table_sp = Table::Make(schema_, columns_);
688   const Table& table = *table_sp;
689 
690   ASSERT_OK_AND_ASSIGN(auto result,
691                        table.SetColumn(0, schema_->field(1), table.column(1)));
692 
693   auto ex_schema =
694       ::arrow::schema({schema_->field(1), schema_->field(1), schema_->field(2)});
695 
696   auto expected =
697       Table::Make(ex_schema, {table.column(1), table.column(1), table.column(2)});
698   ASSERT_TRUE(result->Equals(*expected));
699 }
700 
TEST_F(TestTable,RenameColumns)701 TEST_F(TestTable, RenameColumns) {
702   MakeExample1(10);
703   auto table = Table::Make(schema_, columns_);
704   EXPECT_THAT(table->ColumnNames(), testing::ElementsAre("f0", "f1", "f2"));
705 
706   ASSERT_OK_AND_ASSIGN(auto renamed, table->RenameColumns({"zero", "one", "two"}));
707   EXPECT_THAT(renamed->ColumnNames(), testing::ElementsAre("zero", "one", "two"));
708   ASSERT_OK(renamed->ValidateFull());
709 
710   ASSERT_RAISES(Invalid, table->RenameColumns({"hello", "world"}));
711 }
712 
TEST_F(TestTable,RemoveColumnEmpty)713 TEST_F(TestTable, RemoveColumnEmpty) {
714   // ARROW-1865
715   const int64_t length = 10;
716 
717   auto f0 = field("f0", int32());
718   auto schema = ::arrow::schema({f0});
719   auto a0 = MakeRandomArray<Int32Array>(length);
720 
721   auto table = Table::Make(schema, {std::make_shared<ChunkedArray>(a0)});
722 
723   ASSERT_OK_AND_ASSIGN(auto empty, table->RemoveColumn(0));
724 
725   ASSERT_EQ(table->num_rows(), empty->num_rows());
726 
727   ASSERT_OK_AND_ASSIGN(auto added, empty->AddColumn(0, f0, table->column(0)));
728   ASSERT_EQ(table->num_rows(), added->num_rows());
729 }
730 
TEST_F(TestTable,AddColumn)731 TEST_F(TestTable, AddColumn) {
732   const int64_t length = 10;
733   MakeExample1(length);
734 
735   auto table_sp = Table::Make(schema_, columns_);
736   const Table& table = *table_sp;
737 
738   auto f0 = schema_->field(0);
739 
740   // Some negative tests with invalid index
741   ASSERT_RAISES(Invalid, table.AddColumn(10, f0, columns_[0]));
742   ASSERT_RAISES(Invalid, table.AddColumn(4, f0, columns_[0]));
743   ASSERT_RAISES(Invalid, table.AddColumn(-1, f0, columns_[0]));
744 
745   // Add column with wrong length
746   auto longer_col =
747       std::make_shared<ChunkedArray>(MakeRandomArray<Int32Array>(length + 1));
748   ASSERT_RAISES(Invalid, table.AddColumn(0, f0, longer_col));
749 
750   // Add column 0 in different places
751   ASSERT_OK_AND_ASSIGN(auto result, table.AddColumn(0, f0, columns_[0]));
752   auto ex_schema = ::arrow::schema(
753       {schema_->field(0), schema_->field(0), schema_->field(1), schema_->field(2)});
754 
755   auto expected = Table::Make(
756       ex_schema, {table.column(0), table.column(0), table.column(1), table.column(2)});
757   ASSERT_TRUE(result->Equals(*expected));
758 
759   ASSERT_OK_AND_ASSIGN(result, table.AddColumn(1, f0, columns_[0]));
760   ex_schema = ::arrow::schema(
761       {schema_->field(0), schema_->field(0), schema_->field(1), schema_->field(2)});
762 
763   expected = Table::Make(
764       ex_schema, {table.column(0), table.column(0), table.column(1), table.column(2)});
765   ASSERT_TRUE(result->Equals(*expected));
766 
767   ASSERT_OK_AND_ASSIGN(result, table.AddColumn(2, f0, columns_[0]));
768   ex_schema = ::arrow::schema(
769       {schema_->field(0), schema_->field(1), schema_->field(0), schema_->field(2)});
770   expected = Table::Make(
771       ex_schema, {table.column(0), table.column(1), table.column(0), table.column(2)});
772   ASSERT_TRUE(result->Equals(*expected));
773 
774   ASSERT_OK_AND_ASSIGN(result, table.AddColumn(3, f0, columns_[0]));
775   ex_schema = ::arrow::schema(
776       {schema_->field(0), schema_->field(1), schema_->field(2), schema_->field(0)});
777   expected = Table::Make(
778       ex_schema, {table.column(0), table.column(1), table.column(2), table.column(0)});
779   ASSERT_TRUE(result->Equals(*expected));
780 }
781 
782 class TestRecordBatch : public TestBase {};
783 
TEST_F(TestRecordBatch,Equals)784 TEST_F(TestRecordBatch, Equals) {
785   const int length = 10;
786 
787   auto f0 = field("f0", int32());
788   auto f1 = field("f1", uint8());
789   auto f2 = field("f2", int16());
790 
791   auto metadata = key_value_metadata({"foo"}, {"bar"});
792 
793   std::vector<std::shared_ptr<Field>> fields = {f0, f1, f2};
794   auto schema = ::arrow::schema({f0, f1, f2});
795   auto schema2 = ::arrow::schema({f0, f1});
796   auto schema3 = ::arrow::schema({f0, f1, f2}, metadata);
797 
798   auto a0 = MakeRandomArray<Int32Array>(length);
799   auto a1 = MakeRandomArray<UInt8Array>(length);
800   auto a2 = MakeRandomArray<Int16Array>(length);
801 
802   auto b1 = RecordBatch::Make(schema, length, {a0, a1, a2});
803   auto b2 = RecordBatch::Make(schema3, length, {a0, a1, a2});
804   auto b3 = RecordBatch::Make(schema2, length, {a0, a1});
805   auto b4 = RecordBatch::Make(schema, length, {a0, a1, a1});
806 
807   ASSERT_TRUE(b1->Equals(*b1));
808   ASSERT_FALSE(b1->Equals(*b3));
809   ASSERT_FALSE(b1->Equals(*b4));
810 
811   // Different metadata
812   ASSERT_TRUE(b1->Equals(*b2));
813   ASSERT_FALSE(b1->Equals(*b2, /*check_metadata=*/true));
814 }
815 
TEST_F(TestRecordBatch,Validate)816 TEST_F(TestRecordBatch, Validate) {
817   const int length = 10;
818 
819   auto f0 = field("f0", int32());
820   auto f1 = field("f1", uint8());
821   auto f2 = field("f2", int16());
822 
823   auto schema = ::arrow::schema({f0, f1, f2});
824 
825   auto a0 = MakeRandomArray<Int32Array>(length);
826   auto a1 = MakeRandomArray<UInt8Array>(length);
827   auto a2 = MakeRandomArray<Int16Array>(length);
828   auto a3 = MakeRandomArray<Int16Array>(5);
829 
830   auto b1 = RecordBatch::Make(schema, length, {a0, a1, a2});
831 
832   ASSERT_OK(b1->ValidateFull());
833 
834   // Length mismatch
835   auto b2 = RecordBatch::Make(schema, length, {a0, a1, a3});
836   ASSERT_RAISES(Invalid, b2->ValidateFull());
837 
838   // Type mismatch
839   auto b3 = RecordBatch::Make(schema, length, {a0, a1, a0});
840   ASSERT_RAISES(Invalid, b3->ValidateFull());
841 }
842 
TEST_F(TestRecordBatch,Slice)843 TEST_F(TestRecordBatch, Slice) {
844   const int length = 10;
845 
846   auto f0 = field("f0", int32());
847   auto f1 = field("f1", uint8());
848 
849   std::vector<std::shared_ptr<Field>> fields = {f0, f1};
850   auto schema = ::arrow::schema(fields);
851 
852   auto a0 = MakeRandomArray<Int32Array>(length);
853   auto a1 = MakeRandomArray<UInt8Array>(length);
854 
855   auto batch = RecordBatch::Make(schema, length, {a0, a1});
856 
857   auto batch_slice = batch->Slice(2);
858   auto batch_slice2 = batch->Slice(1, 5);
859 
860   ASSERT_EQ(batch_slice->num_rows(), batch->num_rows() - 2);
861 
862   for (int i = 0; i < batch->num_columns(); ++i) {
863     ASSERT_EQ(2, batch_slice->column(i)->offset());
864     ASSERT_EQ(length - 2, batch_slice->column(i)->length());
865 
866     ASSERT_EQ(1, batch_slice2->column(i)->offset());
867     ASSERT_EQ(5, batch_slice2->column(i)->length());
868   }
869 }
870 
TEST_F(TestRecordBatch,AddColumn)871 TEST_F(TestRecordBatch, AddColumn) {
872   const int length = 10;
873 
874   auto field1 = field("f1", int32());
875   auto field2 = field("f2", uint8());
876   auto field3 = field("f3", int16());
877 
878   auto schema1 = ::arrow::schema({field1, field2});
879   auto schema2 = ::arrow::schema({field2, field3});
880   auto schema3 = ::arrow::schema({field2});
881 
882   auto array1 = MakeRandomArray<Int32Array>(length);
883   auto array2 = MakeRandomArray<UInt8Array>(length);
884   auto array3 = MakeRandomArray<Int16Array>(length);
885 
886   auto batch1 = RecordBatch::Make(schema1, length, {array1, array2});
887   auto batch2 = RecordBatch::Make(schema2, length, {array2, array3});
888   auto batch3 = RecordBatch::Make(schema3, length, {array2});
889 
890   const RecordBatch& batch = *batch3;
891 
892   // Negative tests with invalid index
893   ASSERT_RAISES(Invalid, batch.AddColumn(5, field1, array1));
894   ASSERT_RAISES(Invalid, batch.AddColumn(2, field1, array1));
895   ASSERT_RAISES(Invalid, batch.AddColumn(-1, field1, array1));
896 
897   // Negative test with wrong length
898   auto longer_col = MakeRandomArray<Int32Array>(length + 1);
899   ASSERT_RAISES(Invalid, batch.AddColumn(0, field1, longer_col));
900 
901   // Negative test with mismatch type
902   ASSERT_RAISES(Invalid, batch.AddColumn(0, field1, array2));
903 
904   ASSERT_OK_AND_ASSIGN(auto new_batch, batch.AddColumn(0, field1, array1));
905   AssertBatchesEqual(*new_batch, *batch1);
906 
907   ASSERT_OK_AND_ASSIGN(new_batch, batch.AddColumn(1, field3, array3));
908   AssertBatchesEqual(*new_batch, *batch2);
909 
910   ASSERT_OK_AND_ASSIGN(auto new_batch2, batch.AddColumn(1, "f3", array3));
911   AssertBatchesEqual(*new_batch2, *new_batch);
912 
913   ASSERT_TRUE(new_batch2->schema()->field(1)->nullable());
914 }
915 
TEST_F(TestRecordBatch,RemoveColumn)916 TEST_F(TestRecordBatch, RemoveColumn) {
917   const int length = 10;
918 
919   auto field1 = field("f1", int32());
920   auto field2 = field("f2", uint8());
921   auto field3 = field("f3", int16());
922 
923   auto schema1 = ::arrow::schema({field1, field2, field3});
924   auto schema2 = ::arrow::schema({field2, field3});
925   auto schema3 = ::arrow::schema({field1, field3});
926   auto schema4 = ::arrow::schema({field1, field2});
927 
928   auto array1 = MakeRandomArray<Int32Array>(length);
929   auto array2 = MakeRandomArray<UInt8Array>(length);
930   auto array3 = MakeRandomArray<Int16Array>(length);
931 
932   auto batch1 = RecordBatch::Make(schema1, length, {array1, array2, array3});
933   auto batch2 = RecordBatch::Make(schema2, length, {array2, array3});
934   auto batch3 = RecordBatch::Make(schema3, length, {array1, array3});
935   auto batch4 = RecordBatch::Make(schema4, length, {array1, array2});
936 
937   const RecordBatch& batch = *batch1;
938   std::shared_ptr<RecordBatch> result;
939 
940   // Negative tests with invalid index
941   ASSERT_RAISES(Invalid, batch.RemoveColumn(3));
942   ASSERT_RAISES(Invalid, batch.RemoveColumn(-1));
943 
944   ASSERT_OK_AND_ASSIGN(auto new_batch, batch.RemoveColumn(0));
945   AssertBatchesEqual(*new_batch, *batch2);
946 
947   ASSERT_OK_AND_ASSIGN(new_batch, batch.RemoveColumn(1));
948   AssertBatchesEqual(*new_batch, *batch3);
949 
950   ASSERT_OK_AND_ASSIGN(new_batch, batch.RemoveColumn(2));
951   AssertBatchesEqual(*new_batch, *batch4);
952 }
953 
TEST_F(TestRecordBatch,RemoveColumnEmpty)954 TEST_F(TestRecordBatch, RemoveColumnEmpty) {
955   const int length = 10;
956 
957   auto field1 = field("f1", int32());
958   auto schema1 = ::arrow::schema({field1});
959   auto array1 = MakeRandomArray<Int32Array>(length);
960   auto batch1 = RecordBatch::Make(schema1, length, {array1});
961 
962   ASSERT_OK_AND_ASSIGN(auto empty, batch1->RemoveColumn(0));
963   ASSERT_EQ(batch1->num_rows(), empty->num_rows());
964 
965   ASSERT_OK_AND_ASSIGN(auto added, empty->AddColumn(0, field1, array1));
966   AssertBatchesEqual(*added, *batch1);
967 }
968 
969 class TestTableBatchReader : public TestBase {};
970 
TEST_F(TestTableBatchReader,ReadNext)971 TEST_F(TestTableBatchReader, ReadNext) {
972   ArrayVector c1, c2;
973 
974   auto a1 = MakeRandomArray<Int32Array>(10);
975   auto a2 = MakeRandomArray<Int32Array>(20);
976   auto a3 = MakeRandomArray<Int32Array>(30);
977   auto a4 = MakeRandomArray<Int32Array>(10);
978 
979   auto sch1 = arrow::schema({field("f1", int32()), field("f2", int32())});
980 
981   std::vector<std::shared_ptr<ChunkedArray>> columns;
982 
983   std::shared_ptr<RecordBatch> batch;
984 
985   std::vector<std::shared_ptr<Array>> arrays_1 = {a1, a4, a2};
986   std::vector<std::shared_ptr<Array>> arrays_2 = {a2, a2};
987   columns = {std::make_shared<ChunkedArray>(arrays_1),
988              std::make_shared<ChunkedArray>(arrays_2)};
989   auto t1 = Table::Make(sch1, columns);
990 
991   TableBatchReader i1(*t1);
992 
993   ASSERT_OK(i1.ReadNext(&batch));
994   ASSERT_EQ(10, batch->num_rows());
995 
996   ASSERT_OK(i1.ReadNext(&batch));
997   ASSERT_EQ(10, batch->num_rows());
998 
999   ASSERT_OK(i1.ReadNext(&batch));
1000   ASSERT_EQ(20, batch->num_rows());
1001 
1002   ASSERT_OK(i1.ReadNext(&batch));
1003   ASSERT_EQ(nullptr, batch);
1004 
1005   arrays_1 = {a1};
1006   arrays_2 = {a4};
1007   columns = {std::make_shared<ChunkedArray>(arrays_1),
1008              std::make_shared<ChunkedArray>(arrays_2)};
1009   auto t2 = Table::Make(sch1, columns);
1010 
1011   TableBatchReader i2(*t2);
1012 
1013   ASSERT_OK(i2.ReadNext(&batch));
1014   ASSERT_EQ(10, batch->num_rows());
1015 
1016   // Ensure non-sliced
1017   ASSERT_EQ(a1->data().get(), batch->column_data(0).get());
1018   ASSERT_EQ(a4->data().get(), batch->column_data(1).get());
1019 
1020   ASSERT_OK(i1.ReadNext(&batch));
1021   ASSERT_EQ(nullptr, batch);
1022 }
1023 
TEST_F(TestTableBatchReader,Chunksize)1024 TEST_F(TestTableBatchReader, Chunksize) {
1025   auto a1 = MakeRandomArray<Int32Array>(10);
1026   auto a2 = MakeRandomArray<Int32Array>(20);
1027   auto a3 = MakeRandomArray<Int32Array>(10);
1028 
1029   auto sch1 = arrow::schema({field("f1", int32())});
1030 
1031   std::vector<std::shared_ptr<Array>> arrays = {a1, a2, a3};
1032   auto t1 = Table::Make(sch1, {std::make_shared<ChunkedArray>(arrays)});
1033 
1034   TableBatchReader i1(*t1);
1035 
1036   i1.set_chunksize(15);
1037 
1038   std::shared_ptr<RecordBatch> batch;
1039   ASSERT_OK(i1.ReadNext(&batch));
1040   ASSERT_OK(batch->ValidateFull());
1041   ASSERT_EQ(10, batch->num_rows());
1042 
1043   ASSERT_OK(i1.ReadNext(&batch));
1044   ASSERT_OK(batch->ValidateFull());
1045   ASSERT_EQ(15, batch->num_rows());
1046 
1047   ASSERT_OK(i1.ReadNext(&batch));
1048   ASSERT_OK(batch->ValidateFull());
1049   ASSERT_EQ(5, batch->num_rows());
1050 
1051   ASSERT_OK(i1.ReadNext(&batch));
1052   ASSERT_OK(batch->ValidateFull());
1053   ASSERT_EQ(10, batch->num_rows());
1054 
1055   ASSERT_OK(i1.ReadNext(&batch));
1056   ASSERT_EQ(nullptr, batch);
1057 }
1058 
1059 }  // namespace arrow
1060