github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/testkeys/testkeys_test.go (about) 1 // Copyright 2021 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package testkeys 6 7 import ( 8 "bytes" 9 "fmt" 10 "slices" 11 "testing" 12 13 "github.com/cockroachdb/datadriven" 14 "github.com/stretchr/testify/require" 15 "golang.org/x/exp/rand" 16 ) 17 18 func TestGenerateAlphabetKey(t *testing.T) { 19 testCases := []struct { 20 i int64 21 depth int 22 want string 23 }{ 24 {0, 1, "a"}, 25 {0, 2, "a"}, 26 {0, 3, "a"}, 27 28 {1, 1, "b"}, 29 {2, 1, "c"}, 30 31 {0, 2, "a"}, 32 {1, 2, "aa"}, 33 {2, 2, "ab"}, 34 {3, 2, "ac"}, 35 {4, 2, "b"}, 36 {5, 2, "ba"}, 37 {6, 2, "bb"}, 38 {7, 2, "bc"}, 39 {8, 2, "c"}, 40 {9, 2, "ca"}, 41 {10, 2, "cb"}, 42 {11, 2, "cc"}, 43 } 44 testAlphabet := []byte{byte('a'), byte('b'), byte('c')} 45 testInverseAlphabet := map[byte]int64{byte('a'): 0, byte('b'): 1, byte('c'): 2} 46 47 buf := make([]byte, 10) 48 for _, tc := range testCases { 49 kc := keyCount(len(testAlphabet), tc.depth) 50 n := generateAlphabetKey(buf, testAlphabet, tc.i, kc) 51 got := string(buf[:n]) 52 if got != tc.want { 53 t.Errorf("generateAlphabetKey(%q, %d, %d) = %q, want %q", testAlphabet, tc.i, kc, got, tc.want) 54 } 55 i := computeAlphabetKeyIndex([]byte(got), testInverseAlphabet, tc.depth) 56 if i != tc.i { 57 t.Errorf("computeAlphabetKeyIndex(%q, %d) = %d, want %d", got, tc.depth, i, tc.i) 58 } 59 } 60 } 61 62 func TestKeyCount(t *testing.T) { 63 type params struct { 64 n, l int 65 } 66 testCases := map[params]int64{ 67 {26, 1}: 26, 68 {52, 1}: 52, 69 {2, 2}: 6, 70 {2, 3}: 14, 71 {2, 4}: 30, 72 {3, 2}: 12, 73 } 74 for p, want := range testCases { 75 got := keyCount(p.n, p.l) 76 if got != want { 77 t.Errorf("keyCount(%d, %d) = %d, want %d", p.n, p.l, got, want) 78 } 79 } 80 } 81 82 func TestFullKeyspaces(t *testing.T) { 83 testCases := []struct { 84 ks Keyspace 85 want string 86 }{ 87 { 88 Alpha(1), 89 "a b c d e f g h i j k l m n o p q r s t u v w x y z", 90 }, 91 { 92 alphabet{[]byte("abc"), 2, 0, 0, 1}, 93 "a aa ab ac b ba bb bc c ca cb cc", 94 }, 95 { 96 alphabet{[]byte("abc"), 2, 0, 0, 2}, 97 "a ab b bb c cb", 98 }, 99 { 100 alphabet{[]byte("abc"), 3, 0, 0, 1}, 101 "a aa aaa aab aac ab aba abb abc ac aca acb acc b ba baa bab bac bb bba bbb bbc bc bca bcb bcc c ca caa cab cac cb cba cbb cbc cc cca ccb ccc", 102 }, 103 { 104 alphabet{[]byte("abc"), 3, 7, 10, 1}, 105 "abb abc ac aca acb acc b ba baa bab bac bb bba bbb bbc bc bca bcb bcc c ca caa", 106 }, 107 } 108 for _, tc := range testCases { 109 require.Equal(t, tc.want, keyspaceToString(tc.ks)) 110 } 111 } 112 113 func TestSlice(t *testing.T) { 114 testCases := []struct { 115 orig Keyspace 116 i, j int64 117 want string 118 }{ 119 {Alpha(1), 1, 25, "b c d e f g h i j k l m n o p q r s t u v w x y"}, 120 {Alpha(1).Slice(1, 25), 1, 23, "c d e f g h i j k l m n o p q r s t u v w x"}, 121 {Alpha(1).Slice(1, 25).Slice(1, 23), 10, 22, "m n o p q r s t u v w x"}, 122 } 123 for _, tc := range testCases { 124 got := keyspaceToString(tc.orig.Slice(tc.i, tc.j)) 125 if got != tc.want { 126 t.Errorf("(%q).Slice(%d, %d) = %q, want %q", 127 keyspaceToString(tc.orig), tc.i, tc.j, got, tc.want) 128 } 129 } 130 } 131 132 func TestSuffix(t *testing.T) { 133 ks := Alpha(3) 134 require.Equal(t, "a@1", string(KeyAt(ks, 0, 1))) 135 require.Equal(t, "a@10", string(KeyAt(ks, 0, 10))) 136 require.Equal(t, "aab@5", string(KeyAt(ks, 3, 5))) 137 138 assertCmp := func(want int, a, b []byte) { 139 got := Comparer.Compare(a, b) 140 if got != want { 141 t.Helper() 142 t.Errorf("Compare(%q, %q) = %d, want %d", a, b, got, want) 143 } 144 } 145 146 for i := int64(1); i < ks.Count(); i++ { 147 assertCmp(-1, KeyAt(ks, i-1, 1), KeyAt(ks, i, 1)) 148 assertCmp(-1, Key(ks, i-1), Key(ks, i)) 149 assertCmp(0, Key(ks, i), Key(ks, i)) 150 for ts := int64(2); ts < 11; ts++ { 151 assertCmp(+1, KeyAt(ks, i, ts-1), KeyAt(ks, i, ts)) 152 assertCmp(-1, KeyAt(ks, i-1, ts-1), KeyAt(ks, i, ts)) 153 } 154 } 155 156 // Suffixes should be comparable on their own too. 157 a, b := make([]byte, MaxSuffixLen), make([]byte, MaxSuffixLen) 158 for ts := int64(2); ts < 150; ts++ { 159 an := WriteSuffix(a, ts-1) 160 bn := WriteSuffix(b, ts) 161 assertCmp(+1, a[:an], b[:bn]) 162 } 163 } 164 165 func TestSuffixLen(t *testing.T) { 166 testCases := map[int64]int{ 167 0: 2, 168 1: 2, 169 5: 2, 170 9: 2, 171 10: 3, 172 17: 3, 173 20: 3, 174 99: 3, 175 100: 4, 176 101: 4, 177 999: 4, 178 1000: 5, 179 } 180 for ts, want := range testCases { 181 if got := SuffixLen(ts); got != want { 182 t.Errorf("SuffixLen(%d) = %d, want %d", ts, got, want) 183 } 184 } 185 } 186 187 func TestDivvy(t *testing.T) { 188 var buf bytes.Buffer 189 datadriven.RunTest(t, "testdata/divvy", func(t *testing.T, d *datadriven.TestData) string { 190 buf.Reset() 191 switch d.Cmd { 192 case "divvy": 193 var alphaLen int 194 var portions int64 195 d.ScanArgs(t, "alpha", &alphaLen) 196 d.ScanArgs(t, "portions", &portions) 197 198 input := Alpha(alphaLen) 199 for _, ks := range Divvy(input, portions) { 200 fmt.Fprintln(&buf, keyspaceToString(ks)) 201 } 202 return buf.String() 203 default: 204 return fmt.Sprintf("unrecognized command %q", d.Cmd) 205 } 206 }) 207 } 208 209 func keyspaceToString(ks Keyspace) string { 210 var buf bytes.Buffer 211 b := make([]byte, ks.MaxLen()) 212 for i := int64(0); i < ks.Count(); i++ { 213 n := ks.key(b, i) 214 if i > 0 { 215 buf.WriteRune(' ') 216 } 217 buf.Write(b[:n]) 218 } 219 return buf.String() 220 } 221 222 func TestRandomSeparator(t *testing.T) { 223 rng := rand.New(rand.NewSource(0)) 224 keys := [][]byte{[]byte("a"), []byte("zzz@9")} 225 for n := 0; n < 1000; n++ { 226 i := rng.Intn(len(keys)) 227 j := rng.Intn(len(keys)) 228 for i == j { 229 j = rng.Intn(len(keys)) 230 } 231 if i > j { 232 i, j = j, i 233 } 234 235 a := keys[i] 236 b := keys[j] 237 suffix := rng.Int63n(10) 238 sep := RandomSeparator(nil, a, b, suffix, 3, rng) 239 t.Logf("RandomSeparator(%q, %q, %d) = %q\n", a, b, suffix, sep) 240 if sep == nil { 241 continue 242 } 243 for k := 0; k < len(keys); k++ { 244 v := Comparer.Compare(sep, keys[k]) 245 if k <= i && v <= 0 || k >= j && v >= 0 { 246 t.Fatalf("RandomSeparator(%q, %q, %d) = %q; but Compare(%q,%q) = %d\n", a, b, suffix, sep, sep, keys[k], v) 247 } 248 } 249 keys = append(keys, sep) 250 slices.SortFunc(keys, Comparer.Compare) 251 } 252 }