github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/callgraph/vta/internal/trie/trie_test.go (about)

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.13
     6  // +build go1.13
     7  
     8  package trie
     9  
    10  import (
    11  	"reflect"
    12  	"strconv"
    13  	"testing"
    14  )
    15  
    16  func TestScope(t *testing.T) {
    17  	def := Scope{}
    18  	s0, s1 := newScope(), newScope()
    19  	if s0 == def || s1 == def {
    20  		t.Error("newScope() should never be == to the default scope")
    21  	}
    22  	if s0 == s1 {
    23  		t.Errorf("newScope() %q and %q should not be ==", s0, s1)
    24  	}
    25  	if s0.id == 0 {
    26  		t.Error("s0.id is 0")
    27  	}
    28  	if s1.id == 0 {
    29  		t.Error("s1.id is 0")
    30  	}
    31  	got := s0.String()
    32  	if _, err := strconv.Atoi(got); err != nil {
    33  		t.Errorf("scope{%s}.String() is not an int: got %s with error %s", s0, got, err)
    34  	}
    35  }
    36  
    37  func TestCollision(t *testing.T) {
    38  	var x interface{} = 1
    39  	var y interface{} = 2
    40  
    41  	if v := TakeLhs(x, y); v != x {
    42  		t.Errorf("TakeLhs(%s, %s) got %s. want %s", x, y, v, x)
    43  	}
    44  	if v := TakeRhs(x, y); v != y {
    45  		t.Errorf("TakeRhs(%s, %s) got %s. want %s", x, y, v, y)
    46  	}
    47  }
    48  
    49  func TestDefault(t *testing.T) {
    50  	def := Map{}
    51  
    52  	if def.Size() != 0 {
    53  		t.Errorf("default node has non-0 size %d", def.Size())
    54  	}
    55  	if want, got := (Scope{}), def.Scope(); got != want {
    56  		t.Errorf("default is in a non default scope (%s) from b (%s)", got, want)
    57  	}
    58  	if v, ok := def.Lookup(123); !(v == nil && !ok) {
    59  		t.Errorf("Scope{}.Lookup() = (%s, %v) not (nil, false)", v, ok)
    60  	}
    61  	if !def.Range(func(k uint64, v interface{}) bool {
    62  		t.Errorf("Scope{}.Range() called it callback on %d:%s", k, v)
    63  		return true
    64  	}) {
    65  		t.Error("Scope{}.Range() always iterates through all elements")
    66  	}
    67  
    68  	if got, want := def.String(), "{}"; got != want {
    69  		t.Errorf("Scope{}.String() got %s. want %s", got, want)
    70  	}
    71  
    72  	b := NewBuilder()
    73  	if def == b.Empty() {
    74  		t.Error("Scope{} == to an empty node from a builder")
    75  	}
    76  	if b.Clone(def) != b.Empty() {
    77  		t.Error("b.Clone(Scope{}) should equal b.Empty()")
    78  	}
    79  	if !def.DeepEqual(b.Empty()) {
    80  		t.Error("Scope{}.DeepEqual(b.Empty()) should hold")
    81  	}
    82  }
    83  
    84  func TestBuilders(t *testing.T) {
    85  	b0, b1 := NewBuilder(), NewBuilder()
    86  	if b0.Scope() == b1.Scope() {
    87  		t.Errorf("builders have the same scope %s", b0.Scope())
    88  	}
    89  
    90  	if b0.Empty() == b1.Empty() {
    91  		t.Errorf("empty nodes from different scopes are disequal")
    92  	}
    93  	if !b0.Empty().DeepEqual(b1.Empty()) {
    94  		t.Errorf("empty nodes from different scopes are not DeepEqual")
    95  	}
    96  
    97  	clone := b1.Clone(b0.Empty())
    98  	if clone != b1.Empty() {
    99  		t.Errorf("Clone() empty nodes %v != %v", clone, b1.Empty())
   100  	}
   101  }
   102  
   103  func TestEmpty(t *testing.T) {
   104  	b := NewBuilder()
   105  	e := b.Empty()
   106  	if e.Size() != 0 {
   107  		t.Errorf("empty nodes has non-0 size %d", e.Size())
   108  	}
   109  	if e.Scope() != b.Scope() {
   110  		t.Errorf("b.Empty() is in a different scope (%s) from b (%s)", e.Scope(), b.Scope())
   111  	}
   112  	if v, ok := e.Lookup(123); !(v == nil && !ok) {
   113  		t.Errorf("empty.Lookup() = (%s, %v) not (nil, false)", v, ok)
   114  	}
   115  	if l := e.n.find(123); l != nil {
   116  		t.Errorf("empty.find(123) got %v. want nil", l)
   117  	}
   118  	e.Range(func(k uint64, v interface{}) bool {
   119  		t.Errorf("empty.Range() called it callback on %d:%s", k, v)
   120  		return true
   121  	})
   122  
   123  	want := "{}"
   124  	if got := e.String(); got != want {
   125  		t.Errorf("empty.String(123) got %s. want %s", got, want)
   126  	}
   127  }
   128  
   129  func TestCreate(t *testing.T) {
   130  	// The node orders are printed in lexicographic little-endian.
   131  	b := NewBuilder()
   132  	for _, c := range []struct {
   133  		m    map[uint64]interface{}
   134  		want string
   135  	}{
   136  		{
   137  			map[uint64]interface{}{},
   138  			"{}",
   139  		},
   140  		{
   141  			map[uint64]interface{}{1: "a"},
   142  			"{1: a}",
   143  		},
   144  		{
   145  			map[uint64]interface{}{2: "b", 1: "a"},
   146  			"{1: a, 2: b}",
   147  		},
   148  		{
   149  			map[uint64]interface{}{1: "x", 4: "y", 5: "z"},
   150  			"{1: x, 4: y, 5: z}",
   151  		},
   152  	} {
   153  		m := b.Create(c.m)
   154  		if got := m.String(); got != c.want {
   155  			t.Errorf("Create(%v) got %q. want %q ", c.m, got, c.want)
   156  		}
   157  	}
   158  }
   159  
   160  func TestElems(t *testing.T) {
   161  	b := NewBuilder()
   162  	for _, orig := range []map[uint64]interface{}{
   163  		{},
   164  		{1: "a"},
   165  		{1: "a", 2: "b"},
   166  		{1: "x", 4: "y", 5: "z"},
   167  		{1: "x", 4: "y", 5: "z", 123: "abc"},
   168  	} {
   169  		m := b.Create(orig)
   170  		if elems := Elems(m); !reflect.DeepEqual(orig, elems) {
   171  			t.Errorf("Elems(%v) got %q. want %q ", m, elems, orig)
   172  		}
   173  	}
   174  }
   175  
   176  func TestRange(t *testing.T) {
   177  	b := NewBuilder()
   178  	m := b.Create(map[uint64]interface{}{1: "x", 3: "y", 5: "z", 6: "stop", 8: "a"})
   179  
   180  	calls := 0
   181  	cb := func(k uint64, v interface{}) bool {
   182  		t.Logf("visiting (%d, %v)", k, v)
   183  		calls++
   184  		return k%2 != 0 // stop after the first even number.
   185  	}
   186  	// The nodes are visited in increasing order.
   187  	all := m.Range(cb)
   188  	if all {
   189  		t.Error("expected to stop early")
   190  	}
   191  	want := 4
   192  	if calls != want {
   193  		t.Errorf("# of callbacks (%d) was expected to equal %d (1 + # of evens)",
   194  			calls, want)
   195  	}
   196  }
   197  
   198  func TestDeepEqual(t *testing.T) {
   199  	for _, m := range []map[uint64]interface{}{
   200  		{},
   201  		{1: "x"},
   202  		{1: "x", 2: "y"},
   203  	} {
   204  		l := NewBuilder().Create(m)
   205  		r := NewBuilder().Create(m)
   206  		if !l.DeepEqual(r) {
   207  			t.Errorf("Expect %v to be DeepEqual() to %v", l, r)
   208  		}
   209  	}
   210  }
   211  
   212  func TestNotDeepEqual(t *testing.T) {
   213  	for _, c := range []struct {
   214  		left  map[uint64]interface{}
   215  		right map[uint64]interface{}
   216  	}{
   217  		{
   218  			map[uint64]interface{}{1: "x"},
   219  			map[uint64]interface{}{},
   220  		},
   221  		{
   222  			map[uint64]interface{}{},
   223  			map[uint64]interface{}{1: "y"},
   224  		},
   225  		{
   226  			map[uint64]interface{}{1: "x"},
   227  			map[uint64]interface{}{1: "y"},
   228  		},
   229  		{
   230  			map[uint64]interface{}{1: "x"},
   231  			map[uint64]interface{}{1: "x", 2: "Y"},
   232  		},
   233  		{
   234  			map[uint64]interface{}{1: "x", 2: "Y"},
   235  			map[uint64]interface{}{1: "x"},
   236  		},
   237  		{
   238  			map[uint64]interface{}{1: "x", 2: "y"},
   239  			map[uint64]interface{}{1: "x", 2: "Y"},
   240  		},
   241  	} {
   242  		l := NewBuilder().Create(c.left)
   243  		r := NewBuilder().Create(c.right)
   244  		if l.DeepEqual(r) {
   245  			t.Errorf("Expect %v to be !DeepEqual() to %v", l, r)
   246  		}
   247  	}
   248  }
   249  
   250  func TestMerge(t *testing.T) {
   251  	b := NewBuilder()
   252  	for _, c := range []struct {
   253  		left  map[uint64]interface{}
   254  		right map[uint64]interface{}
   255  		want  string
   256  	}{
   257  		{
   258  			map[uint64]interface{}{},
   259  			map[uint64]interface{}{},
   260  			"{}",
   261  		},
   262  		{
   263  			map[uint64]interface{}{},
   264  			map[uint64]interface{}{1: "a"},
   265  			"{1: a}",
   266  		},
   267  		{
   268  			map[uint64]interface{}{1: "a"},
   269  			map[uint64]interface{}{},
   270  			"{1: a}",
   271  		},
   272  		{
   273  			map[uint64]interface{}{1: "a", 2: "b"},
   274  			map[uint64]interface{}{},
   275  			"{1: a, 2: b}",
   276  		},
   277  		{
   278  			map[uint64]interface{}{1: "x"},
   279  			map[uint64]interface{}{1: "y"},
   280  			"{1: x}", // default collision is left
   281  		},
   282  		{
   283  			map[uint64]interface{}{1: "x"},
   284  			map[uint64]interface{}{2: "y"},
   285  			"{1: x, 2: y}",
   286  		},
   287  		{
   288  			map[uint64]interface{}{4: "y", 5: "z"},
   289  			map[uint64]interface{}{1: "x"},
   290  			"{1: x, 4: y, 5: z}",
   291  		},
   292  		{
   293  			map[uint64]interface{}{1: "x", 5: "z"},
   294  			map[uint64]interface{}{4: "y"},
   295  			"{1: x, 4: y, 5: z}",
   296  		},
   297  		{
   298  			map[uint64]interface{}{1: "x", 4: "y"},
   299  			map[uint64]interface{}{5: "z"},
   300  			"{1: x, 4: y, 5: z}",
   301  		},
   302  		{
   303  			map[uint64]interface{}{1: "a", 4: "c"},
   304  			map[uint64]interface{}{2: "b", 5: "d"},
   305  			"{1: a, 2: b, 4: c, 5: d}",
   306  		},
   307  		{
   308  			map[uint64]interface{}{1: "a", 4: "c"},
   309  			map[uint64]interface{}{2: "b", 5 + 8: "d"},
   310  			"{1: a, 2: b, 4: c, 13: d}",
   311  		},
   312  		{
   313  			map[uint64]interface{}{2: "b", 5 + 8: "d"},
   314  			map[uint64]interface{}{1: "a", 4: "c"},
   315  			"{1: a, 2: b, 4: c, 13: d}",
   316  		},
   317  		{
   318  			map[uint64]interface{}{1: "a", 4: "c"},
   319  			map[uint64]interface{}{2: "b", 5 + 8: "d"},
   320  			"{1: a, 2: b, 4: c, 13: d}",
   321  		},
   322  		{
   323  			map[uint64]interface{}{2: "b", 5 + 8: "d"},
   324  			map[uint64]interface{}{1: "a", 4: "c"},
   325  			"{1: a, 2: b, 4: c, 13: d}",
   326  		},
   327  		{
   328  			map[uint64]interface{}{2: "b", 5 + 8: "d"},
   329  			map[uint64]interface{}{2: "", 3: "a"},
   330  			"{2: b, 3: a, 13: d}",
   331  		},
   332  
   333  		{
   334  			// crafted for `!prefixesOverlap(p, m, q, n)`
   335  			left:  map[uint64]interface{}{1: "a", 2 + 1: "b"},
   336  			right: map[uint64]interface{}{4 + 1: "c", 4 + 2: "d"},
   337  			// p: 5, m: 2 q: 1, n: 2
   338  			want: "{1: a, 3: b, 5: c, 6: d}",
   339  		},
   340  		{
   341  			// crafted for `ord(m, n) && !zeroBit(q, m)`
   342  			left:  map[uint64]interface{}{8 + 2 + 1: "a", 16 + 4: "b"},
   343  			right: map[uint64]interface{}{16 + 8 + 2 + 1: "c", 16 + 8 + 4 + 2 + 1: "d"},
   344  			// left: p: 15, m: 16
   345  			// right: q: 27, n: 4
   346  			want: "{11: a, 20: b, 27: c, 31: d}",
   347  		},
   348  		{
   349  			// crafted for `ord(n, m) && !zeroBit(p, n)`
   350  			// p: 6, m: 1 q: 5, n: 2
   351  			left:  map[uint64]interface{}{4 + 2: "b", 4 + 2 + 1: "c"},
   352  			right: map[uint64]interface{}{4: "a", 4 + 2 + 1: "dropped"},
   353  			want:  "{4: a, 6: b, 7: c}",
   354  		},
   355  	} {
   356  		l, r := b.Create(c.left), b.Create(c.right)
   357  		m := b.Merge(l, r)
   358  		if got := m.String(); got != c.want {
   359  			t.Errorf("Merge(%s, %s) got %q. want %q ", l, r, got, c.want)
   360  		}
   361  	}
   362  }
   363  
   364  func TestIntersect(t *testing.T) {
   365  	// Most of the test cases go after specific branches of intersect.
   366  	b := NewBuilder()
   367  	for _, c := range []struct {
   368  		left  map[uint64]interface{}
   369  		right map[uint64]interface{}
   370  		want  string
   371  	}{
   372  		{
   373  			left:  map[uint64]interface{}{10: "a", 39: "b"},
   374  			right: map[uint64]interface{}{10: "A", 39: "B", 75: "C"},
   375  			want:  "{10: a, 39: b}",
   376  		},
   377  		{
   378  			left:  map[uint64]interface{}{10: "a", 39: "b"},
   379  			right: map[uint64]interface{}{},
   380  			want:  "{}",
   381  		},
   382  		{
   383  			left:  map[uint64]interface{}{},
   384  			right: map[uint64]interface{}{10: "A", 39: "B", 75: "C"},
   385  			want:  "{}",
   386  		},
   387  		{ // m == n && p == q  && left.(*empty) case
   388  			left:  map[uint64]interface{}{4: 1, 6: 3, 10: 8, 15: "on left"},
   389  			right: map[uint64]interface{}{0: 8, 7: 6, 11: 0, 15: "on right"},
   390  			want:  "{15: on left}",
   391  		},
   392  		{ // m == n && p == q  && right.(*empty) case
   393  			left:  map[uint64]interface{}{0: "on left", 1: 2, 2: 3, 3: 1, 7: 3},
   394  			right: map[uint64]interface{}{0: "on right", 5: 1, 6: 8},
   395  			want:  "{0: on left}",
   396  		},
   397  		{ // m == n && p == q  &&  both left and right are not empty
   398  			left:  map[uint64]interface{}{1: "a", 2: "b", 3: "c"},
   399  			right: map[uint64]interface{}{0: "A", 1: "B", 2: "C"},
   400  			want:  "{1: a, 2: b}",
   401  		},
   402  		{ // m == n && p == q  &&  both left and right are not empty
   403  			left:  map[uint64]interface{}{1: "a", 2: "b", 3: "c"},
   404  			right: map[uint64]interface{}{0: "A", 1: "B", 2: "C"},
   405  			want:  "{1: a, 2: b}",
   406  		},
   407  		{ // !prefixesOverlap(p, m, q, n)
   408  			// p = 1, m = 2, q = 5, n = 2
   409  			left:  map[uint64]interface{}{0b001: 1, 0b011: 3},
   410  			right: map[uint64]interface{}{0b100: 4, 0b111: 7},
   411  			want:  "{}",
   412  		},
   413  		{ // ord(m, n) && zeroBit(q, m)
   414  			// p = 3, m = 4, q = 0, n = 1
   415  			left:  map[uint64]interface{}{0b010: 2, 0b101: 5},
   416  			right: map[uint64]interface{}{0b000: 0, 0b001: 1},
   417  			want:  "{}",
   418  		},
   419  
   420  		{ // ord(m, n) && !zeroBit(q, m)
   421  			// p = 29, m = 2, q = 30, n = 1
   422  			left: map[uint64]interface{}{
   423  				0b11101: "29",
   424  				0b11110: "30",
   425  			},
   426  			right: map[uint64]interface{}{
   427  				0b11110: "30 on right",
   428  				0b11111: "31",
   429  			},
   430  			want: "{30: 30}",
   431  		},
   432  		{ // ord(n, m) && zeroBit(p, n)
   433  			// p = 5, m = 2, q = 3, n = 4
   434  			left:  map[uint64]interface{}{0b000: 0, 0b001: 1},
   435  			right: map[uint64]interface{}{0b010: 2, 0b101: 5},
   436  			want:  "{}",
   437  		},
   438  		{ // default case
   439  			// p = 5, m = 2, q = 3, n = 4
   440  			left:  map[uint64]interface{}{0b100: 1, 0b110: 3},
   441  			right: map[uint64]interface{}{0b000: 8, 0b111: 6},
   442  			want:  "{}",
   443  		},
   444  	} {
   445  		l, r := b.Create(c.left), b.Create(c.right)
   446  		m := b.Intersect(l, r)
   447  		if got := m.String(); got != c.want {
   448  			t.Errorf("Intersect(%s, %s) got %q. want %q ", l, r, got, c.want)
   449  		}
   450  	}
   451  }
   452  
   453  func TestIntersectWith(t *testing.T) {
   454  	b := NewBuilder()
   455  	l := b.Create(map[uint64]interface{}{10: 2.0, 39: 32.0})
   456  	r := b.Create(map[uint64]interface{}{10: 6.0, 39: 10.0, 75: 1.0})
   457  
   458  	prodIfDifferent := func(x interface{}, y interface{}) interface{} {
   459  		if x, ok := x.(float64); ok {
   460  			if y, ok := y.(float64); ok {
   461  				if x == y {
   462  					return x
   463  				}
   464  				return x * y
   465  			}
   466  		}
   467  		return x
   468  	}
   469  
   470  	m := b.IntersectWith(prodIfDifferent, l, r)
   471  
   472  	want := "{10: %!s(float64=12), 39: %!s(float64=320)}"
   473  	if got := m.String(); got != want {
   474  		t.Errorf("IntersectWith(min, %s, %s) got %q. want %q ", l, r, got, want)
   475  	}
   476  }
   477  
   478  func TestRemove(t *testing.T) {
   479  	// Most of the test cases go after specific branches of intersect.
   480  	b := NewBuilder()
   481  	for _, c := range []struct {
   482  		m    map[uint64]interface{}
   483  		key  uint64
   484  		want string
   485  	}{
   486  		{map[uint64]interface{}{}, 10, "{}"},
   487  		{map[uint64]interface{}{10: "a"}, 10, "{}"},
   488  		{map[uint64]interface{}{39: "b"}, 10, "{39: b}"},
   489  		// Branch cases:
   490  		// !matchPrefix(kp, br.prefix, br.branching)
   491  		{map[uint64]interface{}{10: "a", 39: "b"}, 128, "{10: a, 39: b}"},
   492  		// case: left == br.left && right == br.right
   493  		{map[uint64]interface{}{10: "a", 39: "b"}, 16, "{10: a, 39: b}"},
   494  		// left updated and is empty.
   495  		{map[uint64]interface{}{10: "a", 39: "b"}, 10, "{39: b}"},
   496  		// right updated and is empty.
   497  		{map[uint64]interface{}{10: "a", 39: "b"}, 39, "{10: a}"},
   498  		// final b.mkBranch(...) case.
   499  		{map[uint64]interface{}{10: "a", 39: "b", 128: "c"}, 39, "{10: a, 128: c}"},
   500  	} {
   501  		pre := b.Create(c.m)
   502  		post := b.Remove(pre, c.key)
   503  		if got := post.String(); got != c.want {
   504  			t.Errorf("Remove(%s, %d) got %q. want %q ", pre, c.key, got, c.want)
   505  		}
   506  	}
   507  }
   508  
   509  func TestRescope(t *testing.T) {
   510  	b := NewBuilder()
   511  	l := b.Create(map[uint64]interface{}{10: "a", 39: "b"})
   512  	r := b.Create(map[uint64]interface{}{10: "A", 39: "B", 75: "C"})
   513  
   514  	b.Rescope()
   515  
   516  	m := b.Intersect(l, r)
   517  	if got, want := m.String(), "{10: a, 39: b}"; got != want {
   518  		t.Errorf("Intersect(%s, %s) got %q. want %q", l, r, got, want)
   519  	}
   520  	if m.Scope() == l.Scope() {
   521  		t.Errorf("m.Scope() = %v should not equal l.Scope() = %v", m.Scope(), l.Scope())
   522  	}
   523  	if m.Scope() == r.Scope() {
   524  		t.Errorf("m.Scope() = %v should not equal r.Scope() = %v", m.Scope(), r.Scope())
   525  	}
   526  }
   527  
   528  func TestSharing(t *testing.T) {
   529  	b := NewBuilder()
   530  	l := b.Create(map[uint64]interface{}{0: "a", 1: "b"})
   531  	r := b.Create(map[uint64]interface{}{1: "B", 2: "C"})
   532  
   533  	rleftold := r.n.(*branch).left
   534  
   535  	m := b.Merge(l, r)
   536  	if mleft := m.n.(*branch).left; mleft != l.n {
   537  		t.Errorf("unexpected value for left branch of %v. want %v got %v", m, l, mleft)
   538  	}
   539  
   540  	if rleftnow := r.n.(*branch).left; rleftnow != rleftold {
   541  		t.Errorf("r.n.(*branch).left was modified by the Merge operation. was %v now %v", rleftold, rleftnow)
   542  	}
   543  }