github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/col/coldata/testutils.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package coldata
    12  
    13  import (
    14  	"bytes"
    15  	"fmt"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/col/typeconv"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  // testingT is a private interface that mirrors the testing.TB methods used.
    23  // testing.TB cannot be used directly since testing is an illegal import.
    24  // TODO(asubiotto): Remove AssertEquivalentBatches' dependency on testing.TB by
    25  //  checking for equality and returning a diff string instead of operating on
    26  //  testing.TB.
    27  type testingT interface {
    28  	Helper()
    29  	Errorf(format string, args ...interface{})
    30  	Fatal(args ...interface{})
    31  	Fatalf(format string, args ...interface{})
    32  	FailNow()
    33  }
    34  
    35  // AssertEquivalentBatches is a testing function that asserts that expected and
    36  // actual are equivalent.
    37  func AssertEquivalentBatches(t testingT, expected, actual Batch) {
    38  	t.Helper()
    39  
    40  	if actual.Selection() != nil {
    41  		t.Fatal("violated invariant that batches have no selection vectors")
    42  	}
    43  	require.Equal(t, expected.Length(), actual.Length())
    44  	if expected.Length() == 0 {
    45  		// The schema of a zero-length batch is undefined, so the rest of the check
    46  		// is not required.
    47  		return
    48  	}
    49  	require.Equal(t, expected.Width(), actual.Width())
    50  	for colIdx := 0; colIdx < expected.Width(); colIdx++ {
    51  		// Verify equality of ColVecs (this includes nulls). Since the coldata.Vec
    52  		// backing array is always of coldata.BatchSize() due to the scratch batch
    53  		// that the converter keeps around, the coldata.Vec needs to be sliced to
    54  		// the first length elements to match on length, otherwise the check will
    55  		// fail.
    56  		expectedVec := expected.ColVec(colIdx)
    57  		actualVec := actual.ColVec(colIdx)
    58  		require.Equal(t, expectedVec.Type(), actualVec.Type())
    59  		require.Equal(
    60  			t,
    61  			expectedVec.Nulls().Slice(0, expected.Length()),
    62  			actualVec.Nulls().Slice(0, actual.Length()),
    63  		)
    64  		canonicalTypeFamily := expectedVec.CanonicalTypeFamily()
    65  		if canonicalTypeFamily == types.BytesFamily {
    66  			// Cannot use require.Equal for this type.
    67  			// TODO(asubiotto): Again, why not?
    68  			expectedBytes := expectedVec.Bytes().Window(0, expected.Length())
    69  			resultBytes := actualVec.Bytes().Window(0, actual.Length())
    70  			require.Equal(t, expectedBytes.Len(), resultBytes.Len())
    71  			for i := 0; i < expectedBytes.Len(); i++ {
    72  				if !bytes.Equal(expectedBytes.Get(i), resultBytes.Get(i)) {
    73  					t.Fatalf("bytes mismatch at index %d:\nexpected:\n%sactual:\n%s", i, expectedBytes, resultBytes)
    74  				}
    75  			}
    76  		} else if canonicalTypeFamily == types.TimestampTZFamily {
    77  			// Cannot use require.Equal for this type.
    78  			// TODO(yuzefovich): Again, why not?
    79  			expectedTimestamp := expectedVec.Timestamp()[0:expected.Length()]
    80  			resultTimestamp := actualVec.Timestamp()[0:actual.Length()]
    81  			require.Equal(t, len(expectedTimestamp), len(resultTimestamp))
    82  			for i := range expectedTimestamp {
    83  				if !expectedTimestamp[i].Equal(resultTimestamp[i]) {
    84  					t.Fatalf("Timestamp mismatch at index %d:\nexpected:\n%sactual:\n%s", i, expectedTimestamp[i], resultTimestamp[i])
    85  				}
    86  			}
    87  		} else if canonicalTypeFamily == types.IntervalFamily {
    88  			// Cannot use require.Equal for this type.
    89  			// TODO(yuzefovich): Again, why not?
    90  			expectedInterval := expectedVec.Interval()[0:expected.Length()]
    91  			resultInterval := actualVec.Interval()[0:actual.Length()]
    92  			require.Equal(t, len(expectedInterval), len(resultInterval))
    93  			for i := range expectedInterval {
    94  				if expectedInterval[i].Compare(resultInterval[i]) != 0 {
    95  					t.Fatalf("Interval mismatch at index %d:\nexpected:\n%sactual:\n%s", i, expectedInterval[i], resultInterval[i])
    96  				}
    97  			}
    98  		} else if expectedVec.CanonicalTypeFamily() == typeconv.DatumVecCanonicalTypeFamily {
    99  			// Cannot use require.Equal for this type.
   100  			expectedDatum := expectedVec.Datum().Slice(0 /* start */, expected.Length())
   101  			resultDatum := actualVec.Datum().Slice(0 /* start */, actual.Length())
   102  			require.Equal(t, expectedDatum.Len(), resultDatum.Len())
   103  			for i := 0; i < expectedDatum.Len(); i++ {
   104  				expected := expectedDatum.Get(i).(fmt.Stringer).String()
   105  				actual := resultDatum.Get(i).(fmt.Stringer).String()
   106  				if expected != actual {
   107  					t.Fatalf("Datum mismatch at index %d:\nexpected:\n%sactual:\n%s", i, expectedDatum.Get(i), resultDatum.Get(i))
   108  				}
   109  			}
   110  		} else {
   111  			require.Equal(
   112  				t,
   113  				expectedVec.Window(0, expected.Length()),
   114  				actualVec.Window(0, actual.Length()),
   115  			)
   116  		}
   117  	}
   118  }