mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-15 04:35:17 +00:00
253 lines
5.8 KiB
Go
253 lines
5.8 KiB
Go
|
// Copyright 2021 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||
|
// of this source code is governed by a BSD-style license that can be found in
|
||
|
// the LICENSE file.
|
||
|
|
||
|
package testkeys
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"slices"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/cockroachdb/datadriven"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
"golang.org/x/exp/rand"
|
||
|
)
|
||
|
|
||
|
func TestGenerateAlphabetKey(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
i int64
|
||
|
depth int
|
||
|
want string
|
||
|
}{
|
||
|
{0, 1, "a"},
|
||
|
{0, 2, "a"},
|
||
|
{0, 3, "a"},
|
||
|
|
||
|
{1, 1, "b"},
|
||
|
{2, 1, "c"},
|
||
|
|
||
|
{0, 2, "a"},
|
||
|
{1, 2, "aa"},
|
||
|
{2, 2, "ab"},
|
||
|
{3, 2, "ac"},
|
||
|
{4, 2, "b"},
|
||
|
{5, 2, "ba"},
|
||
|
{6, 2, "bb"},
|
||
|
{7, 2, "bc"},
|
||
|
{8, 2, "c"},
|
||
|
{9, 2, "ca"},
|
||
|
{10, 2, "cb"},
|
||
|
{11, 2, "cc"},
|
||
|
}
|
||
|
testAlphabet := []byte{byte('a'), byte('b'), byte('c')}
|
||
|
testInverseAlphabet := map[byte]int64{byte('a'): 0, byte('b'): 1, byte('c'): 2}
|
||
|
|
||
|
buf := make([]byte, 10)
|
||
|
for _, tc := range testCases {
|
||
|
kc := keyCount(len(testAlphabet), tc.depth)
|
||
|
n := generateAlphabetKey(buf, testAlphabet, tc.i, kc)
|
||
|
got := string(buf[:n])
|
||
|
if got != tc.want {
|
||
|
t.Errorf("generateAlphabetKey(%q, %d, %d) = %q, want %q", testAlphabet, tc.i, kc, got, tc.want)
|
||
|
}
|
||
|
i := computeAlphabetKeyIndex([]byte(got), testInverseAlphabet, tc.depth)
|
||
|
if i != tc.i {
|
||
|
t.Errorf("computeAlphabetKeyIndex(%q, %d) = %d, want %d", got, tc.depth, i, tc.i)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestKeyCount(t *testing.T) {
|
||
|
type params struct {
|
||
|
n, l int
|
||
|
}
|
||
|
testCases := map[params]int64{
|
||
|
{26, 1}: 26,
|
||
|
{52, 1}: 52,
|
||
|
{2, 2}: 6,
|
||
|
{2, 3}: 14,
|
||
|
{2, 4}: 30,
|
||
|
{3, 2}: 12,
|
||
|
}
|
||
|
for p, want := range testCases {
|
||
|
got := keyCount(p.n, p.l)
|
||
|
if got != want {
|
||
|
t.Errorf("keyCount(%d, %d) = %d, want %d", p.n, p.l, got, want)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFullKeyspaces(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
ks Keyspace
|
||
|
want string
|
||
|
}{
|
||
|
{
|
||
|
Alpha(1),
|
||
|
"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",
|
||
|
},
|
||
|
{
|
||
|
alphabet{[]byte("abc"), 2, 0, 0, 1},
|
||
|
"a aa ab ac b ba bb bc c ca cb cc",
|
||
|
},
|
||
|
{
|
||
|
alphabet{[]byte("abc"), 2, 0, 0, 2},
|
||
|
"a ab b bb c cb",
|
||
|
},
|
||
|
{
|
||
|
alphabet{[]byte("abc"), 3, 0, 0, 1},
|
||
|
"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",
|
||
|
},
|
||
|
{
|
||
|
alphabet{[]byte("abc"), 3, 7, 10, 1},
|
||
|
"abb abc ac aca acb acc b ba baa bab bac bb bba bbb bbc bc bca bcb bcc c ca caa",
|
||
|
},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
require.Equal(t, tc.want, keyspaceToString(tc.ks))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSlice(t *testing.T) {
|
||
|
testCases := []struct {
|
||
|
orig Keyspace
|
||
|
i, j int64
|
||
|
want string
|
||
|
}{
|
||
|
{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"},
|
||
|
{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"},
|
||
|
{Alpha(1).Slice(1, 25).Slice(1, 23), 10, 22, "m n o p q r s t u v w x"},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
got := keyspaceToString(tc.orig.Slice(tc.i, tc.j))
|
||
|
if got != tc.want {
|
||
|
t.Errorf("(%q).Slice(%d, %d) = %q, want %q",
|
||
|
keyspaceToString(tc.orig), tc.i, tc.j, got, tc.want)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSuffix(t *testing.T) {
|
||
|
ks := Alpha(3)
|
||
|
require.Equal(t, "a@1", string(KeyAt(ks, 0, 1)))
|
||
|
require.Equal(t, "a@10", string(KeyAt(ks, 0, 10)))
|
||
|
require.Equal(t, "aab@5", string(KeyAt(ks, 3, 5)))
|
||
|
|
||
|
assertCmp := func(want int, a, b []byte) {
|
||
|
got := Comparer.Compare(a, b)
|
||
|
if got != want {
|
||
|
t.Helper()
|
||
|
t.Errorf("Compare(%q, %q) = %d, want %d", a, b, got, want)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for i := int64(1); i < ks.Count(); i++ {
|
||
|
assertCmp(-1, KeyAt(ks, i-1, 1), KeyAt(ks, i, 1))
|
||
|
assertCmp(-1, Key(ks, i-1), Key(ks, i))
|
||
|
assertCmp(0, Key(ks, i), Key(ks, i))
|
||
|
for ts := int64(2); ts < 11; ts++ {
|
||
|
assertCmp(+1, KeyAt(ks, i, ts-1), KeyAt(ks, i, ts))
|
||
|
assertCmp(-1, KeyAt(ks, i-1, ts-1), KeyAt(ks, i, ts))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Suffixes should be comparable on their own too.
|
||
|
a, b := make([]byte, MaxSuffixLen), make([]byte, MaxSuffixLen)
|
||
|
for ts := int64(2); ts < 150; ts++ {
|
||
|
an := WriteSuffix(a, ts-1)
|
||
|
bn := WriteSuffix(b, ts)
|
||
|
assertCmp(+1, a[:an], b[:bn])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSuffixLen(t *testing.T) {
|
||
|
testCases := map[int64]int{
|
||
|
0: 2,
|
||
|
1: 2,
|
||
|
5: 2,
|
||
|
9: 2,
|
||
|
10: 3,
|
||
|
17: 3,
|
||
|
20: 3,
|
||
|
99: 3,
|
||
|
100: 4,
|
||
|
101: 4,
|
||
|
999: 4,
|
||
|
1000: 5,
|
||
|
}
|
||
|
for ts, want := range testCases {
|
||
|
if got := SuffixLen(ts); got != want {
|
||
|
t.Errorf("SuffixLen(%d) = %d, want %d", ts, got, want)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestDivvy(t *testing.T) {
|
||
|
var buf bytes.Buffer
|
||
|
datadriven.RunTest(t, "testdata/divvy", func(t *testing.T, d *datadriven.TestData) string {
|
||
|
buf.Reset()
|
||
|
switch d.Cmd {
|
||
|
case "divvy":
|
||
|
var alphaLen int
|
||
|
var portions int64
|
||
|
d.ScanArgs(t, "alpha", &alphaLen)
|
||
|
d.ScanArgs(t, "portions", &portions)
|
||
|
|
||
|
input := Alpha(alphaLen)
|
||
|
for _, ks := range Divvy(input, portions) {
|
||
|
fmt.Fprintln(&buf, keyspaceToString(ks))
|
||
|
}
|
||
|
return buf.String()
|
||
|
default:
|
||
|
return fmt.Sprintf("unrecognized command %q", d.Cmd)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func keyspaceToString(ks Keyspace) string {
|
||
|
var buf bytes.Buffer
|
||
|
b := make([]byte, ks.MaxLen())
|
||
|
for i := int64(0); i < ks.Count(); i++ {
|
||
|
n := ks.key(b, i)
|
||
|
if i > 0 {
|
||
|
buf.WriteRune(' ')
|
||
|
}
|
||
|
buf.Write(b[:n])
|
||
|
}
|
||
|
return buf.String()
|
||
|
}
|
||
|
|
||
|
func TestRandomSeparator(t *testing.T) {
|
||
|
rng := rand.New(rand.NewSource(0))
|
||
|
keys := [][]byte{[]byte("a"), []byte("zzz@9")}
|
||
|
for n := 0; n < 1000; n++ {
|
||
|
i := rng.Intn(len(keys))
|
||
|
j := rng.Intn(len(keys))
|
||
|
for i == j {
|
||
|
j = rng.Intn(len(keys))
|
||
|
}
|
||
|
if i > j {
|
||
|
i, j = j, i
|
||
|
}
|
||
|
|
||
|
a := keys[i]
|
||
|
b := keys[j]
|
||
|
suffix := rng.Int63n(10)
|
||
|
sep := RandomSeparator(nil, a, b, suffix, 3, rng)
|
||
|
t.Logf("RandomSeparator(%q, %q, %d) = %q\n", a, b, suffix, sep)
|
||
|
if sep == nil {
|
||
|
continue
|
||
|
}
|
||
|
for k := 0; k < len(keys); k++ {
|
||
|
v := Comparer.Compare(sep, keys[k])
|
||
|
if k <= i && v <= 0 || k >= j && v >= 0 {
|
||
|
t.Fatalf("RandomSeparator(%q, %q, %d) = %q; but Compare(%q,%q) = %d\n", a, b, suffix, sep, sep, keys[k], v)
|
||
|
}
|
||
|
}
|
||
|
keys = append(keys, sep)
|
||
|
slices.SortFunc(keys, Comparer.Compare)
|
||
|
}
|
||
|
}
|