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 }