gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/trie/trie_test.go (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package trie
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/google/go-cmp/cmp"
    21  	"github.com/google/go-cmp/cmp/cmpopts"
    22  )
    23  
    24  type Entry struct {
    25  	Key   string
    26  	Value string
    27  }
    28  
    29  func collectPrefixes(tr *Trie, key string) []Entry {
    30  	arr := make([]Entry, 0)
    31  	tr.FindPrefixes(key, func(p string, v any) bool {
    32  		arr = append(arr, Entry{Key: p, Value: v.(string)})
    33  		return true
    34  	})
    35  	return arr
    36  }
    37  
    38  func collectSuffixes(tr *Trie, key string) []Entry {
    39  	arr := make([]Entry, 0)
    40  	tr.FindSuffixes(key, func(p string, v any) bool {
    41  		arr = append(arr, Entry{Key: p, Value: v.(string)})
    42  		return true
    43  	})
    44  	return arr
    45  }
    46  
    47  func sortEntries(a Entry, b Entry) bool {
    48  	return a.Key < b.Key
    49  }
    50  
    51  func TestEmpty(t *testing.T) {
    52  	tr := New()
    53  	if tr.Size() != 0 {
    54  		t.Errorf("tr.Size() = %d; want 0", tr.Size())
    55  	}
    56  
    57  	arr := collectPrefixes(tr, "foo")
    58  	if d := cmp.Diff([]Entry{}, arr); d != "" {
    59  		t.Errorf("collectPrefixes(tr, 'foo') returned diff (-want +got):\n%s", d)
    60  	}
    61  
    62  	arr = collectSuffixes(tr, "foo")
    63  	if d := cmp.Diff([]Entry{}, arr); d != "" {
    64  		t.Errorf("collectSuffixes(tr, '') returned diff (-want +got):\n%s", d)
    65  	}
    66  
    67  	arr = collectPrefixes(tr, "")
    68  	if d := cmp.Diff([]Entry{}, arr); d != "" {
    69  		t.Errorf("collectPrefixes(tr, '') returned diff (-want +got):\n%s", d)
    70  	}
    71  
    72  	arr = collectSuffixes(tr, "")
    73  	if d := cmp.Diff([]Entry{}, arr); d != "" {
    74  		t.Errorf("collectSuffixes(tr, '') returned diff (-want +got):\n%s", d)
    75  	}
    76  }
    77  
    78  func TestAscendingSearch(t *testing.T) {
    79  	tr := New()
    80  	tr.SetValue("a", "value a")
    81  	tr.SetValue("ab", "value ab")
    82  	tr.SetValue("abc", "value abc")
    83  	tr.SetValue("abcd", "value abcd")
    84  	tr.SetValue("abcde", "value abcde")
    85  
    86  	expected := []Entry{
    87  		{Key: "a", Value: "value a"},
    88  		{Key: "ab", Value: "value ab"},
    89  		{Key: "abc", Value: "value abc"},
    90  		{Key: "abcd", Value: "value abcd"},
    91  		{Key: "abcde", Value: "value abcde"}}
    92  	arr := collectPrefixes(tr, "abcdef")
    93  	if d := cmp.Diff(expected, arr); d != "" {
    94  		t.Errorf("collectPrefixes(tr, 'abcdef') returned diff (-want +got):\n%s", d)
    95  	}
    96  
    97  	suffixTests := []struct {
    98  		key     string
    99  		entries []Entry
   100  	}{
   101  		{"", expected},
   102  		{"zzz", []Entry{}},
   103  		{"a", expected},
   104  		{"ab", expected[1:]},
   105  		{"abc", expected[2:]},
   106  		{"abd", []Entry{}},
   107  		{"abcd", expected[3:]},
   108  		{"abcde", expected[4:]},
   109  	}
   110  	for _, tt := range suffixTests {
   111  		t.Run(tt.key, func(t *testing.T) {
   112  			arr := collectSuffixes(tr, tt.key)
   113  			if d := cmp.Diff(tt.entries, arr, cmpopts.SortSlices(sortEntries)); d != "" {
   114  				t.Errorf("collectSuffixes(tr, %q) returned sorted diff (-want +got):\n%s", tt.key, d)
   115  			}
   116  		})
   117  	}
   118  }
   119  
   120  func TestRoot(t *testing.T) {
   121  	tr := New()
   122  	tr.SetValue("", "root value")
   123  	if tr.Size() != 1 {
   124  		t.Errorf("tr.Size() = %d; want 1", tr.Size())
   125  	}
   126  
   127  	expected := []Entry{{Key: "", Value: "root value"}}
   128  	arr := collectPrefixes(tr, "foo")
   129  	if d := cmp.Diff(expected, arr); d != "" {
   130  		t.Errorf("collectPrefixes(tr, 'foo') returned diff (-want +got):\n%s", d)
   131  	}
   132  
   133  	arr = collectPrefixes(tr, "")
   134  	if d := cmp.Diff(expected, arr); d != "" {
   135  		t.Errorf("collectPrefixes(tr, '') returned diff (-want +got):\n%s", d)
   136  	}
   137  }
   138  
   139  func TestMultiplePrefixes(t *testing.T) {
   140  	tr := New()
   141  	tr.SetValue("foo", "old foo value")
   142  	if tr.Size() != 1 {
   143  		t.Errorf("tr.Size() = %d; want 1", tr.Size())
   144  	}
   145  	tr.SetValue("foobar", "foobar value")
   146  	if tr.Size() != 2 {
   147  		t.Errorf("tr.Size() = %d; want 2", tr.Size())
   148  	}
   149  	tr.SetValue("qux", "qux value")
   150  	if tr.Size() != 3 {
   151  		t.Errorf("tr.Size() = %d; want 3", tr.Size())
   152  	}
   153  	tr.SetValue("foo", "foo value")
   154  	if tr.Size() != 3 {
   155  		t.Errorf("tr.Size() = %d; want 3", tr.Size())
   156  	}
   157  
   158  	fooEntry := Entry{Key: "foo", Value: "foo value"}
   159  	foobarEntry := Entry{Key: "foobar", Value: "foobar value"}
   160  	quxEntry := Entry{Key: "qux", Value: "qux value"}
   161  
   162  	prefixTests := []struct {
   163  		key     string
   164  		entries []Entry
   165  	}{
   166  		{"foobar", []Entry{fooEntry, foobarEntry}},
   167  		{"fooba", []Entry{fooEntry}},
   168  		{"foo", []Entry{fooEntry}},
   169  		{"quxiho", []Entry{quxEntry}},
   170  		{"fo", []Entry{}},
   171  		{"qu", []Entry{}},
   172  		{"nowhere", []Entry{}},
   173  		{"", []Entry{}},
   174  	}
   175  	for _, tt := range prefixTests {
   176  		t.Run(tt.key, func(t *testing.T) {
   177  			arr := collectPrefixes(tr, tt.key)
   178  			if d := cmp.Diff(tt.entries, arr); d != "" {
   179  				t.Errorf("collectPrefixes(tr, %q) returned diff (-want +got):\n%s", tt.key, d)
   180  			}
   181  		})
   182  	}
   183  }