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
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
24 "github.com/apache/arrow/go/v6/arrow"
25 "github.com/apache/arrow/go/v6/arrow/array"
26 "github.com/apache/arrow/go/v6/arrow/float16"
27 "github.com/apache/arrow/go/v6/arrow/internal/arrdata"
28 "github.com/apache/arrow/go/v6/arrow/memory"
29 "github.com/stretchr/testify/assert"
32 func TestArrayEqual(t *testing.T) {
33 for name, recs := range arrdata.Records {
34 t.Run(name, func(t *testing.T) {
36 schema := rec.Schema()
37 for i, col := range rec.Columns() {
38 t.Run(schema.Field(i).Name, func(t *testing.T) {
40 if !array.ArrayEqual(arr, arr) {
41 t.Fatalf("identical arrays should compare equal:\narray=%v", arr)
43 sub1 := array.NewSlice(arr, 1, int64(arr.Len()))
46 sub2 := array.NewSlice(arr, 0, int64(arr.Len()-1))
49 if array.ArrayEqual(sub1, sub2) && name != "nulls" {
50 t.Fatalf("non-identical arrays should not compare equal:\nsub1=%v\nsub2=%v\narrf=%v\n", sub1, sub2, arr)
58 func TestArraySliceEqual(t *testing.T) {
59 for name, recs := range arrdata.Records {
60 t.Run(name, func(t *testing.T) {
62 schema := rec.Schema()
63 for i, col := range rec.Columns() {
64 t.Run(schema.Field(i).Name, func(t *testing.T) {
66 if !array.ArraySliceEqual(
67 arr, 0, int64(arr.Len()),
68 arr, 0, int64(arr.Len()),
70 t.Fatalf("identical slices should compare equal:\narray=%v", arr)
72 sub1 := array.NewSlice(arr, 1, int64(arr.Len()))
75 sub2 := array.NewSlice(arr, 0, int64(arr.Len()-1))
78 if array.ArraySliceEqual(sub1, 0, int64(sub1.Len()), sub2, 0, int64(sub2.Len())) && name != "nulls" {
79 t.Fatalf("non-identical slices should not compare equal:\nsub1=%v\nsub2=%v\narrf=%v\n", sub1, sub2, arr)
87 func TestArrayApproxEqual(t *testing.T) {
88 for name, recs := range arrdata.Records {
89 t.Run(name, func(t *testing.T) {
91 schema := rec.Schema()
92 for i, col := range rec.Columns() {
93 t.Run(schema.Field(i).Name, func(t *testing.T) {
95 if !array.ArrayApproxEqual(arr, arr) {
96 t.Fatalf("identical arrays should compare equal:\narray=%v", arr)
98 sub1 := array.NewSlice(arr, 1, int64(arr.Len()))
101 sub2 := array.NewSlice(arr, 0, int64(arr.Len()-1))
104 if array.ArrayApproxEqual(sub1, sub2) && name != "nulls" {
105 t.Fatalf("non-identical arrays should not compare equal:\nsub1=%v\nsub2=%v\narrf=%v\n", sub1, sub2, arr)
113 func TestArrayApproxEqualFloats(t *testing.T) {
114 f16sFrom := func(vs []float64) []float16.Num {
115 o := make([]float16.Num, len(vs))
116 for i, v := range vs {
117 o[i] = float16.New(float32(v))
122 for _, tc := range []struct {
126 opts []array.EqualOption
131 a1: f16sFrom([]float64{1, 2, 3, 4, 5, 6}),
132 a2: f16sFrom([]float64{1, 2, 3, 4, 5, 6}),
137 a1: f16sFrom([]float64{1, 2, 3, 4, 5, 6}),
138 a2: f16sFrom([]float64{1, 2, 3, 4, 5, 7}),
143 a1: f16sFrom([]float64{1, 2, 3, 4, 5, 6}),
144 a2: f16sFrom([]float64{1, 2, 3, 4, 5, 7}),
145 opts: []array.EqualOption{array.WithAbsTolerance(1)},
150 a1: f16sFrom([]float64{1, 2, 3, 4, 5, 6}),
151 a2: f16sFrom([]float64{1, 2, 3, 4, 5, math.NaN()}),
156 a1: f16sFrom([]float64{1, 2, 3, 4, 5, 6}),
157 a2: f16sFrom([]float64{1, 2, 3, 4, 5, math.NaN()}),
158 opts: []array.EqualOption{array.WithNaNsEqual(true)},
163 a1: f16sFrom([]float64{1, 2, 3, 4, 5, math.NaN()}),
164 a2: f16sFrom([]float64{1, 2, 3, 4, 5, math.NaN()}),
165 opts: []array.EqualOption{array.WithNaNsEqual(true)},
169 name: "f16-nan-no-tol",
170 a1: f16sFrom([]float64{1, 2, 3, 4, 5, math.NaN()}),
171 a2: f16sFrom([]float64{1, 2, 3, 4, 6, math.NaN()}),
172 opts: []array.EqualOption{array.WithNaNsEqual(true)},
177 a1: f16sFrom([]float64{1, 2, 3, 4, 5, math.NaN()}),
178 a2: f16sFrom([]float64{1, 2, 3, 4, 6, math.NaN()}),
179 opts: []array.EqualOption{array.WithNaNsEqual(true), array.WithAbsTolerance(1)},
184 a1: []float32{1, 2, 3, 4, 5, 6},
185 a2: []float32{1, 2, 3, 4, 5, 6},
190 a1: []float32{1, 2, 3, 4, 5, 6},
191 a2: []float32{1, 2, 3, 4, 5, 7},
196 a1: []float32{1, 2, 3, 4, 5, 6},
197 a2: []float32{1, 2, 3, 4, 5, 7},
198 opts: []array.EqualOption{array.WithAbsTolerance(1)},
203 a1: []float32{1, 2, 3, 4, 5, 6},
204 a2: []float32{1, 2, 3, 4, 5, float32(math.NaN())},
209 a1: []float32{1, 2, 3, 4, 5, 6},
210 a2: []float32{1, 2, 3, 4, 5, float32(math.NaN())},
211 opts: []array.EqualOption{array.WithNaNsEqual(true)},
216 a1: []float32{1, 2, 3, 4, 5, float32(math.NaN())},
217 a2: []float32{1, 2, 3, 4, 5, float32(math.NaN())},
218 opts: []array.EqualOption{array.WithNaNsEqual(true)},
222 name: "f32-nan-no-tol",
223 a1: []float32{1, 2, 3, 4, 5, float32(math.NaN())},
224 a2: []float32{1, 2, 3, 4, 6, float32(math.NaN())},
225 opts: []array.EqualOption{array.WithNaNsEqual(true)},
230 a1: []float32{1, 2, 3, 4, 5, float32(math.NaN())},
231 a2: []float32{1, 2, 3, 4, 6, float32(math.NaN())},
232 opts: []array.EqualOption{array.WithNaNsEqual(true), array.WithAbsTolerance(1)},
237 a1: []float64{1, 2, 3, 4, 5, 6},
238 a2: []float64{1, 2, 3, 4, 5, 6},
243 a1: []float64{1, 2, 3, 4, 5, 6},
244 a2: []float64{1, 2, 3, 4, 5, 7},
249 a1: []float64{1, 2, 3, 4, 5, 6},
250 a2: []float64{1, 2, 3, 4, 5, 7},
251 opts: []array.EqualOption{array.WithAbsTolerance(1)},
256 a1: []float64{1, 2, 3, 4, 5, 6},
257 a2: []float64{1, 2, 3, 4, 5, math.NaN()},
262 a1: []float64{1, 2, 3, 4, 5, 6},
263 a2: []float64{1, 2, 3, 4, 5, math.NaN()},
264 opts: []array.EqualOption{array.WithNaNsEqual(true)},
269 a1: []float64{1, 2, 3, 4, 5, math.NaN()},
270 a2: []float64{1, 2, 3, 4, 5, math.NaN()},
271 opts: []array.EqualOption{array.WithNaNsEqual(true)},
275 name: "f64-nan-no-tol",
276 a1: []float64{1, 2, 3, 4, 5, math.NaN()},
277 a2: []float64{1, 2, 3, 4, 6, math.NaN()},
278 opts: []array.EqualOption{array.WithNaNsEqual(true)},
283 a1: []float64{1, 2, 3, 4, 5, math.NaN()},
284 a2: []float64{1, 2, 3, 4, 6, math.NaN()},
285 opts: []array.EqualOption{array.WithNaNsEqual(true), array.WithAbsTolerance(1)},
289 t.Run(tc.name, func(t *testing.T) {
290 mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
291 defer mem.AssertSize(t, 0)
293 a1 := arrayOf(mem, tc.a1, nil)
295 a2 := arrayOf(mem, tc.a2, nil)
298 if got, want := array.ArrayApproxEqual(a1, a2, tc.opts...), tc.want; got != want {
299 t.Fatalf("invalid comparison: got=%v, want=%v\na1: %v\na2: %v\n", got, want, a1, a2)
305 func arrayOf(mem memory.Allocator, a interface{}, valids []bool) array.Interface {
307 mem = memory.NewGoAllocator()
310 switch a := a.(type) {
312 bldr := array.NewFloat16Builder(mem)
315 bldr.AppendValues(a, valids)
316 return bldr.NewFloat16Array()
319 bldr := array.NewFloat32Builder(mem)
322 bldr.AppendValues(a, valids)
323 return bldr.NewFloat32Array()
326 bldr := array.NewFloat64Builder(mem)
329 bldr.AppendValues(a, valids)
330 return bldr.NewFloat64Array()
333 panic(fmt.Errorf("arrdata: invalid data slice type %T", a))
337 func TestArrayEqualBaseArray(t *testing.T) {
338 mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
339 defer mem.AssertSize(t, 0)
341 b1 := array.NewBooleanBuilder(mem)
344 a1 := b1.NewBooleanArray()
347 b2 := array.NewBooleanBuilder(mem)
349 a2 := b2.NewBooleanArray()
352 if array.ArrayEqual(a1, a2) {
353 t.Errorf("two arrays with different lengths must not be equal")
356 b3 := array.NewBooleanBuilder(mem)
359 a3 := b3.NewBooleanArray()
362 if array.ArrayEqual(a1, a3) {
363 t.Errorf("two arrays with different number of null values must not be equal")
366 b4 := array.NewInt32Builder(mem)
369 a4 := b4.NewInt32Array()
372 if array.ArrayEqual(a1, a4) {
373 t.Errorf("two arrays with different types must not be equal")
376 b5 := array.NewBooleanBuilder(mem)
380 a5 := b5.NewBooleanArray()
384 if array.ArrayEqual(a1, a5) {
385 t.Errorf("two arrays with different validity bitmaps must not be equal")
389 func TestArrayEqualNull(t *testing.T) {
390 mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
391 defer mem.AssertSize(t, 0)
393 null := array.NewNull(0)
396 if !array.ArrayEqual(null, null) {
397 t.Fatalf("identical arrays should compare equal")
400 n0 := array.NewNull(10)
403 n1 := array.NewNull(10)
406 if !array.ArrayEqual(n0, n0) {
407 t.Fatalf("identical arrays should compare equal")
409 if !array.ArrayEqual(n1, n1) {
410 t.Fatalf("identical arrays should compare equal")
412 if !array.ArrayEqual(n0, n1) || !array.ArrayEqual(n1, n0) {
413 t.Fatalf("n0 and n1 should compare equal")
416 sub07 := array.NewSlice(n0, 0, 7)
417 defer sub07.Release()
418 sub08 := array.NewSlice(n0, 0, 8)
419 defer sub08.Release()
420 sub19 := array.NewSlice(n0, 1, 9)
421 defer sub19.Release()
423 if !array.ArrayEqual(sub08, sub19) {
424 t.Fatalf("sub08 and sub19 should compare equal")
427 if array.ArrayEqual(sub08, sub07) {
428 t.Fatalf("sub08 and sub07 should not compare equal")
432 func TestArrayEqualMaskedArray(t *testing.T) {
433 mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
434 defer mem.AssertSize(t, 0)
436 ab := array.NewInt32Builder(mem)
439 valids := []bool{false, false, false, false}
440 ab.AppendValues([]int32{1, 2, 0, 4}, valids)
442 a1 := ab.NewInt32Array()
445 ab.AppendValues([]int32{1, 2, 3, 4}, valids)
446 a2 := ab.NewInt32Array()
449 if !array.ArrayEqual(a1, a1) || !array.ArrayEqual(a2, a2) {
450 t.Errorf("an array must be equal to itself")
453 if !array.ArrayEqual(a1, a2) {
454 t.Errorf("%v must be equal to %v", a1, a2)
458 func TestArrayEqualDifferentMaskedValues(t *testing.T) {
459 // test 2 int32 arrays, with same nulls (but different masked values) compare equal.
460 mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
461 defer mem.AssertSize(t, 0)
463 ab := array.NewInt32Builder(mem)
466 valids := []bool{true, true, false, true}
467 ab.AppendValues([]int32{1, 2, 0, 4}, valids)
469 a1 := ab.NewInt32Array()
472 ab.AppendValues([]int32{1, 2, 3, 4}, valids)
473 a2 := ab.NewInt32Array()
476 if !array.ArrayEqual(a1, a1) || !array.ArrayEqual(a2, a2) {
477 t.Errorf("an array must be equal to itself")
480 if !array.ArrayEqual(a1, a2) {
481 t.Errorf("%v must be equal to %v", a1, a2)
485 func TestRecordEqual(t *testing.T) {
486 for name, recs := range arrdata.Records {
487 t.Run(name, func(t *testing.T) {
490 if !array.RecordEqual(rec0, rec0) {
491 t.Fatalf("identical records should compare equal:\nrecord:\n%v", rec0)
494 if array.RecordEqual(rec0, rec1) && name != "nulls" {
495 t.Fatalf("non-identical records should not compare equal:\nrec0:\n%v\nrec1:\n%v", rec0, rec1)
498 sub00 := rec0.NewSlice(0, recs[0].NumRows()-1)
499 defer sub00.Release()
500 sub01 := rec0.NewSlice(1, recs[0].NumRows())
501 defer sub01.Release()
503 if array.RecordEqual(sub00, sub01) && name != "nulls" {
504 t.Fatalf("non-identical records should not compare equal:\nsub0:\n%v\nsub1:\n%v", sub00, sub01)
510 func TestRecordApproxEqual(t *testing.T) {
511 for name, recs := range arrdata.Records {
512 t.Run(name, func(t *testing.T) {
515 if !array.RecordApproxEqual(rec0, rec0) {
516 t.Fatalf("identical records should compare equal:\nrecord:\n%v", rec0)
519 if array.RecordApproxEqual(rec0, rec1) && name != "nulls" {
520 t.Fatalf("non-identical records should not compare equal:\nrec0:\n%v\nrec1:\n%v", rec0, rec1)
523 sub00 := rec0.NewSlice(0, recs[0].NumRows()-1)
524 defer sub00.Release()
525 sub01 := rec0.NewSlice(1, recs[0].NumRows())
526 defer sub01.Release()
528 if array.RecordApproxEqual(sub00, sub01) && name != "nulls" {
529 t.Fatalf("non-identical records should not compare equal:\nsub0:\n%v\nsub1:\n%v", sub00, sub01)
535 func TestChunkedEqual(t *testing.T) {
536 for name, recs := range arrdata.Records {
537 t.Run(name, func(t *testing.T) {
538 tbl := array.NewTableFromRecords(recs[0].Schema(), recs)
541 for i := 0; i < int(tbl.NumCols()); i++ {
542 if !array.ChunkedEqual(tbl.Column(i).Data(), tbl.Column(i).Data()) && name != "nulls" {
543 t.Fatalf("identical chunked arrays should compare as equal:\narr:%v\n", tbl.Column(i).Data())
550 func TestChunkedApproxEqual(t *testing.T) {
551 fb := array.NewFloat64Builder(memory.DefaultAllocator)
554 fb.AppendValues([]float64{1, 2, 3, 4, 5}, nil)
555 f1 := fb.NewFloat64Array()
558 fb.AppendValues([]float64{6, 7}, nil)
559 f2 := fb.NewFloat64Array()
562 fb.AppendValues([]float64{8, 9, 10}, nil)
563 f3 := fb.NewFloat64Array()
566 c1 := array.NewChunked(
567 arrow.PrimitiveTypes.Float64,
568 []array.Interface{f1, f2, f3},
572 fb.AppendValues([]float64{1, 2, 3}, nil)
573 f4 := fb.NewFloat64Array()
576 fb.AppendValues([]float64{4, 5}, nil)
577 f5 := fb.NewFloat64Array()
580 fb.AppendValues([]float64{6, 7, 8, 9}, nil)
581 f6 := fb.NewFloat64Array()
584 fb.AppendValues([]float64{10}, nil)
585 f7 := fb.NewFloat64Array()
588 c2 := array.NewChunked(
589 arrow.PrimitiveTypes.Float64,
590 []array.Interface{f4, f5, f6, f7},
594 assert.True(t, array.ChunkedEqual(c1, c2))
595 assert.True(t, array.ChunkedApproxEqual(c1, c2))
598 func TestTableEqual(t *testing.T) {
599 for name, recs := range arrdata.Records {
600 t.Run(name, func(t *testing.T) {
601 tbl := array.NewTableFromRecords(recs[0].Schema(), recs)
604 if !array.TableEqual(tbl, tbl) {
605 t.Fatalf("identical tables should compare as equal:\tbl:%v\n", tbl)
607 if !array.TableApproxEqual(tbl, tbl) {
608 t.Fatalf("identical tables should compare as approx equal:\tbl:%v\n", tbl)