github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/covering/overlap_merge_test.go (about)

     1  // Copyright 2016 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 covering
    12  
    13  import (
    14  	"bytes"
    15  	"fmt"
    16  	"reflect"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    20  )
    21  
    22  // TODO(dan): Write a simple version of the algorithm that uses the fact that
    23  // the endpoints are small integers (e.g. fill out a [100][]string) and
    24  // use it to cross-check the results. This could also be used to generate tests
    25  // of random inputs.
    26  func TestOverlapCoveringMerge(t *testing.T) {
    27  	defer leaktest.AfterTest(t)()
    28  
    29  	tests := []struct {
    30  		name string
    31  		// inputs is a slice of coverings. The inner slice represents a covering
    32  		// as an even number of ints, which are pairwise endpoints. So (1, 2, 2,
    33  		// 4) means [/1, /2) and [/2, /4).
    34  		inputs [][]byte
    35  		// expectedIntervals is the output ranges in the same format as an input
    36  		// covering.
    37  		expectedIntervals []byte
    38  		// expectedPayloads is the output payloads, corresponding 1:1 with
    39  		// entries in expectedIntervals. Each input range is given an int
    40  		// payload from 0..N-1 where N is the total number of ranges in all
    41  		// input coverings for this test. Each of these is formatted as a string
    42  		// concatenation of these ints.
    43  		//
    44  		// So for covering [1, 2), [2, 3) and covering [1, 3), the output
    45  		// payloads would be "02" for [1, 2) and "12" for [2, 3).
    46  		expectedPayloads []string
    47  	}{
    48  		{"no input",
    49  			[][]byte{},
    50  			nil, nil,
    51  		},
    52  		{"one empty covering",
    53  			[][]byte{{}},
    54  			nil, nil,
    55  		},
    56  		{"two empty coverings",
    57  			[][]byte{{}, {}},
    58  			nil, nil,
    59  		},
    60  		{"one",
    61  			[][]byte{{1, 2}, {}},
    62  			[]byte{1, 2}, []string{"0"},
    63  		},
    64  		{"same",
    65  			[][]byte{{1, 2}, {1, 2}},
    66  			[]byte{1, 2}, []string{"01"},
    67  		},
    68  		{"overlap",
    69  			[][]byte{{1, 3}, {2, 3}},
    70  			[]byte{1, 2, 2, 3}, []string{"0", "01"}},
    71  		{"overlap reversed",
    72  			[][]byte{{2, 3}, {1, 3}},
    73  			[]byte{1, 2, 2, 3}, []string{"1", "01"}},
    74  		{"no overlap",
    75  			[][]byte{{1, 2, 5, 6}, {3, 4}},
    76  			[]byte{1, 2, 3, 4, 5, 6}, []string{"0", "2", "1"},
    77  		},
    78  		{"cockroach range splits and merges",
    79  			[][]byte{{1, 3, 3, 4}, {1, 4}, {1, 2, 2, 4}},
    80  			[]byte{1, 2, 2, 3, 3, 4}, []string{"023", "024", "124"},
    81  		},
    82  		{"godoc example",
    83  			[][]byte{{1, 2, 3, 4, 6, 7}, {1, 5}},
    84  			[]byte{1, 2, 2, 3, 3, 4, 4, 5, 6, 7}, []string{"03", "3", "13", "3", "2"},
    85  		},
    86  		{"empty",
    87  			[][]byte{{1, 2, 2, 2, 2, 2, 4, 5}, {1, 5}},
    88  			[]byte{1, 2, 2, 2, 2, 4, 4, 5}, []string{"04", "124", "4", "34"},
    89  		},
    90  	}
    91  
    92  	for _, test := range tests {
    93  		t.Run(test.name, func(t *testing.T) {
    94  			var payload int
    95  			var inputs []Covering
    96  			for _, endpoints := range test.inputs {
    97  				var c Covering
    98  				for i := 0; i < len(endpoints); i += 2 {
    99  					c = append(c, Range{
   100  						Start:   []byte{endpoints[i]},
   101  						End:     []byte{endpoints[i+1]},
   102  						Payload: payload,
   103  					})
   104  					payload++
   105  				}
   106  				inputs = append(inputs, c)
   107  			}
   108  			var outputIntervals []byte
   109  			var outputPayloads []string
   110  			for _, r := range OverlapCoveringMerge(inputs) {
   111  				outputIntervals = append(outputIntervals, r.Start[0], r.End[0])
   112  				var payload bytes.Buffer
   113  				for _, p := range r.Payload.([]interface{}) {
   114  					fmt.Fprintf(&payload, "%d", p.(int))
   115  				}
   116  				outputPayloads = append(outputPayloads, payload.String())
   117  			}
   118  			if !reflect.DeepEqual(outputIntervals, test.expectedIntervals) {
   119  				t.Errorf("intervals got\n%v\nexpected\n%v", outputIntervals, test.expectedIntervals)
   120  			}
   121  			if !reflect.DeepEqual(outputPayloads, test.expectedPayloads) {
   122  				t.Errorf("payloads got\n%v\nexpected\n%v", outputPayloads, test.expectedPayloads)
   123  			}
   124  		})
   125  	}
   126  }