mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
611 lines
17 KiB
Go
611 lines
17 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package merkledb
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestBranchFactor_Valid(t *testing.T) {
|
|
require := require.New(t)
|
|
for _, bf := range validBranchFactors {
|
|
require.NoError(bf.Valid())
|
|
}
|
|
var empty BranchFactor
|
|
err := empty.Valid()
|
|
require.ErrorIs(err, ErrInvalidBranchFactor)
|
|
}
|
|
|
|
func TestHasPartialByte(t *testing.T) {
|
|
for _, ts := range validTokenSizes {
|
|
t.Run(strconv.Itoa(ts), func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
key := Key{}
|
|
require.False(key.hasPartialByte())
|
|
|
|
if ts == 8 {
|
|
// Tokens are an entire byte so
|
|
// there is never a partial byte.
|
|
key = key.Extend(ToToken(1, ts))
|
|
require.False(key.hasPartialByte())
|
|
key = key.Extend(ToToken(0, ts))
|
|
require.False(key.hasPartialByte())
|
|
return
|
|
}
|
|
|
|
// Fill all but the last token of the first byte.
|
|
for i := 0; i < 8-ts; i += ts {
|
|
key = key.Extend(ToToken(1, ts))
|
|
require.True(key.hasPartialByte())
|
|
}
|
|
|
|
// Fill the last token of the first byte.
|
|
key = key.Extend(ToToken(0, ts))
|
|
require.False(key.hasPartialByte())
|
|
|
|
// Fill the first token of the second byte.
|
|
key = key.Extend(ToToken(0, ts))
|
|
require.True(key.hasPartialByte())
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_Key_Has_Prefix(t *testing.T) {
|
|
type test struct {
|
|
name string
|
|
keyA func(ts int) Key
|
|
keyB func(ts int) Key
|
|
isStrictPrefix bool
|
|
isPrefix bool
|
|
}
|
|
|
|
key := "Key"
|
|
|
|
tests := []test{
|
|
{
|
|
name: "equal keys",
|
|
keyA: func(int) Key { return ToKey([]byte(key)) },
|
|
keyB: func(int) Key { return ToKey([]byte(key)) },
|
|
isPrefix: true,
|
|
isStrictPrefix: false,
|
|
},
|
|
{
|
|
name: "one key has one fewer token",
|
|
keyA: func(int) Key { return ToKey([]byte(key)) },
|
|
keyB: func(ts int) Key {
|
|
return ToKey([]byte(key)).Take(len(key)*8 - ts)
|
|
},
|
|
isPrefix: true,
|
|
isStrictPrefix: true,
|
|
},
|
|
{
|
|
name: "equal keys, both have one fewer token",
|
|
keyA: func(ts int) Key {
|
|
return ToKey([]byte(key)).Take(len(key)*8 - ts)
|
|
},
|
|
keyB: func(ts int) Key {
|
|
return ToKey([]byte(key)).Take(len(key)*8 - ts)
|
|
},
|
|
isPrefix: true,
|
|
isStrictPrefix: false,
|
|
},
|
|
{
|
|
name: "different keys",
|
|
keyA: func(int) Key { return ToKey([]byte{0xF7}) },
|
|
keyB: func(int) Key { return ToKey([]byte{0xF0}) },
|
|
isPrefix: false,
|
|
isStrictPrefix: false,
|
|
},
|
|
{
|
|
name: "same bytes, different lengths",
|
|
keyA: func(ts int) Key {
|
|
return ToKey([]byte{0x10, 0x00}).Take(ts)
|
|
},
|
|
keyB: func(ts int) Key {
|
|
return ToKey([]byte{0x10, 0x00}).Take(ts * 2)
|
|
},
|
|
isPrefix: false,
|
|
isStrictPrefix: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
for _, ts := range validTokenSizes {
|
|
t.Run(tt.name+" ts "+strconv.Itoa(ts), func(t *testing.T) {
|
|
require := require.New(t)
|
|
keyA := tt.keyA(ts)
|
|
keyB := tt.keyB(ts)
|
|
|
|
require.Equal(tt.isPrefix, keyA.HasPrefix(keyB))
|
|
require.Equal(tt.isPrefix, keyA.iteratedHasPrefix(keyB, 0, ts))
|
|
require.Equal(tt.isStrictPrefix, keyA.HasStrictPrefix(keyB))
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func Test_Key_Skip(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
empty := Key{}
|
|
require.Equal(ToKey([]byte{0}).Skip(8), empty)
|
|
for _, ts := range validTokenSizes {
|
|
if ts == 8 {
|
|
continue
|
|
}
|
|
shortKey := ToKey([]byte{0b0101_0101})
|
|
longKey := ToKey([]byte{0b0101_0101, 0b0101_0101})
|
|
for shift := 0; shift < 8; shift += ts {
|
|
skipKey := shortKey.Skip(shift)
|
|
require.Equal(byte(0b0101_0101<<shift), skipKey.value[0])
|
|
|
|
skipKey = longKey.Skip(shift)
|
|
require.Equal(byte(0b0101_0101<<shift+0b0101_0101>>(8-shift)), skipKey.value[0])
|
|
require.Equal(byte(0b0101_0101<<shift), skipKey.value[1])
|
|
}
|
|
}
|
|
|
|
skip := ToKey([]byte{0b0101_0101, 0b1010_1010}).Skip(8)
|
|
require.Len(skip.value, 1)
|
|
require.Equal(byte(0b1010_1010), skip.value[0])
|
|
|
|
skip = ToKey([]byte{0b0101_0101, 0b1010_1010, 0b0101_0101}).Skip(8)
|
|
require.Len(skip.value, 2)
|
|
require.Equal(byte(0b1010_1010), skip.value[0])
|
|
require.Equal(byte(0b0101_0101), skip.value[1])
|
|
}
|
|
|
|
func Test_Key_Take(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
require.Equal(Key{}, ToKey([]byte{0}).Take(0))
|
|
|
|
for _, ts := range validTokenSizes {
|
|
if ts == 8 {
|
|
continue
|
|
}
|
|
key := ToKey([]byte{0b0101_0101})
|
|
for length := ts; length <= 8; length += ts {
|
|
take := key.Take(length)
|
|
require.Equal(length, take.length)
|
|
shift := 8 - length
|
|
require.Equal(byte((0b0101_0101>>shift)<<shift), take.value[0])
|
|
}
|
|
}
|
|
|
|
take := ToKey([]byte{0b0101_0101, 0b1010_1010}).Take(8)
|
|
require.Len(take.value, 1)
|
|
require.Equal(byte(0b0101_0101), take.value[0])
|
|
}
|
|
|
|
func Test_Key_Token(t *testing.T) {
|
|
type test struct {
|
|
name string
|
|
inputBytes []byte
|
|
assertTokens func(*require.Assertions, Key)
|
|
}
|
|
|
|
tests := []test{
|
|
{
|
|
name: "branch factor 2",
|
|
inputBytes: []byte{0b0_1_0_1_0_1_0_1, 0b1_0_1_0_1_0_1_0},
|
|
assertTokens: func(require *require.Assertions, key Key) {
|
|
require.Equal(byte(0), key.Token(0, 1))
|
|
require.Equal(byte(1), key.Token(1, 1))
|
|
require.Equal(byte(0), key.Token(2, 1))
|
|
require.Equal(byte(1), key.Token(3, 1))
|
|
require.Equal(byte(0), key.Token(4, 1))
|
|
require.Equal(byte(1), key.Token(5, 1))
|
|
require.Equal(byte(0), key.Token(6, 1))
|
|
require.Equal(byte(1), key.Token(7, 1)) // end first byte
|
|
require.Equal(byte(1), key.Token(8, 1))
|
|
require.Equal(byte(0), key.Token(9, 1))
|
|
require.Equal(byte(1), key.Token(10, 1))
|
|
require.Equal(byte(0), key.Token(11, 1))
|
|
require.Equal(byte(1), key.Token(12, 1))
|
|
require.Equal(byte(0), key.Token(13, 1))
|
|
require.Equal(byte(1), key.Token(14, 1))
|
|
require.Equal(byte(0), key.Token(15, 1)) // end second byte
|
|
},
|
|
},
|
|
{
|
|
name: "branch factor 4",
|
|
inputBytes: []byte{0b00_01_10_11, 0b11_10_01_00},
|
|
assertTokens: func(require *require.Assertions, key Key) {
|
|
require.Equal(byte(0), key.Token(0, 2)) // 00
|
|
require.Equal(byte(1), key.Token(2, 2)) // 01
|
|
require.Equal(byte(2), key.Token(4, 2)) // 10
|
|
require.Equal(byte(3), key.Token(6, 2)) // 11 end first byte
|
|
require.Equal(byte(3), key.Token(8, 2)) // 11
|
|
require.Equal(byte(2), key.Token(10, 2)) // 10
|
|
require.Equal(byte(1), key.Token(12, 2)) // 01
|
|
require.Equal(byte(0), key.Token(14, 2)) // 00 end second byte
|
|
},
|
|
},
|
|
{
|
|
name: "branch factor 16",
|
|
inputBytes: []byte{
|
|
0b0000_0001,
|
|
0b0010_0011,
|
|
0b0100_0101,
|
|
0b0110_0111,
|
|
0b1000_1001,
|
|
0b1010_1011,
|
|
0b1100_1101,
|
|
0b1110_1111,
|
|
},
|
|
assertTokens: func(require *require.Assertions, key Key) {
|
|
for i := 0; i < 16; i++ {
|
|
require.Equal(byte(i), key.Token(i*4, 4))
|
|
}
|
|
},
|
|
},
|
|
}
|
|
|
|
for i := 0; i < 256; i++ {
|
|
tests = append(tests, test{
|
|
name: fmt.Sprintf("branch factor 256, byte %d", i),
|
|
inputBytes: []byte{byte(i)},
|
|
assertTokens: func(require *require.Assertions, key Key) {
|
|
require.Equal(byte(i), key.Token(0, 8))
|
|
},
|
|
})
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
require := require.New(t)
|
|
key := ToKey(tt.inputBytes)
|
|
tt.assertTokens(require, key)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_Key_Append(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
key := ToKey([]byte{})
|
|
for _, bf := range validBranchFactors {
|
|
size := BranchFactorToTokenSize[bf]
|
|
for i := 0; i < int(bf); i++ {
|
|
appendedKey := key.Extend(ToToken(byte(i), size), ToToken(byte(i/2), size))
|
|
require.Equal(byte(i), appendedKey.Token(0, size))
|
|
require.Equal(byte(i/2), appendedKey.Token(size, size))
|
|
}
|
|
}
|
|
}
|
|
|
|
func Test_Key_AppendExtend(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
key2 := ToKey([]byte{0b1000_0000}).Take(1)
|
|
p := ToKey([]byte{0b01010101})
|
|
extendedP := key2.Extend(ToToken(0, 1), p)
|
|
require.Equal([]byte{0b10010101, 0b01000_000}, extendedP.Bytes())
|
|
require.Equal(byte(1), extendedP.Token(0, 1))
|
|
require.Equal(byte(0), extendedP.Token(1, 1))
|
|
require.Equal(byte(0), extendedP.Token(2, 1))
|
|
require.Equal(byte(1), extendedP.Token(3, 1))
|
|
require.Equal(byte(0), extendedP.Token(4, 1))
|
|
require.Equal(byte(1), extendedP.Token(5, 1))
|
|
require.Equal(byte(0), extendedP.Token(6, 1))
|
|
require.Equal(byte(1), extendedP.Token(7, 1))
|
|
require.Equal(byte(0), extendedP.Token(8, 1))
|
|
require.Equal(byte(1), extendedP.Token(9, 1))
|
|
|
|
p = ToKey([]byte{0b0101_0101, 0b1000_0000}).Take(9)
|
|
extendedP = key2.Extend(ToToken(0, 1), p)
|
|
require.Equal([]byte{0b1001_0101, 0b0110_0000}, extendedP.Bytes())
|
|
require.Equal(byte(1), extendedP.Token(0, 1))
|
|
require.Equal(byte(0), extendedP.Token(1, 1))
|
|
require.Equal(byte(0), extendedP.Token(2, 1))
|
|
require.Equal(byte(1), extendedP.Token(3, 1))
|
|
require.Equal(byte(0), extendedP.Token(4, 1))
|
|
require.Equal(byte(1), extendedP.Token(5, 1))
|
|
require.Equal(byte(0), extendedP.Token(6, 1))
|
|
require.Equal(byte(1), extendedP.Token(7, 1))
|
|
require.Equal(byte(0), extendedP.Token(8, 1))
|
|
require.Equal(byte(1), extendedP.Token(9, 1))
|
|
require.Equal(byte(1), extendedP.Token(10, 1))
|
|
|
|
key4 := ToKey([]byte{0b0100_0000}).Take(2)
|
|
p = ToKey([]byte{0b0101_0101})
|
|
extendedP = key4.Extend(ToToken(0, 2), p)
|
|
require.Equal([]byte{0b0100_0101, 0b0101_0000}, extendedP.Bytes())
|
|
require.Equal(byte(1), extendedP.Token(0, 2))
|
|
require.Equal(byte(0), extendedP.Token(2, 2))
|
|
require.Equal(byte(1), extendedP.Token(4, 2))
|
|
require.Equal(byte(1), extendedP.Token(6, 2))
|
|
require.Equal(byte(1), extendedP.Token(8, 2))
|
|
require.Equal(byte(1), extendedP.Token(10, 2))
|
|
|
|
key16 := ToKey([]byte{0b0001_0000}).Take(4)
|
|
p = ToKey([]byte{0b0001_0001})
|
|
extendedP = key16.Extend(ToToken(0, 4), p)
|
|
require.Equal([]byte{0b0001_0000, 0b0001_0001}, extendedP.Bytes())
|
|
require.Equal(byte(1), extendedP.Token(0, 4))
|
|
require.Equal(byte(0), extendedP.Token(4, 4))
|
|
require.Equal(byte(1), extendedP.Token(8, 4))
|
|
require.Equal(byte(1), extendedP.Token(12, 4))
|
|
|
|
p = ToKey([]byte{0b0001_0001, 0b0001_0001})
|
|
extendedP = key16.Extend(ToToken(0, 4), p)
|
|
require.Equal([]byte{0b0001_0000, 0b0001_0001, 0b0001_0001}, extendedP.Bytes())
|
|
require.Equal(byte(1), extendedP.Token(0, 4))
|
|
require.Equal(byte(0), extendedP.Token(4, 4))
|
|
require.Equal(byte(1), extendedP.Token(8, 4))
|
|
require.Equal(byte(1), extendedP.Token(12, 4))
|
|
require.Equal(byte(1), extendedP.Token(16, 4))
|
|
require.Equal(byte(1), extendedP.Token(20, 4))
|
|
|
|
key256 := ToKey([]byte{0b0000_0001})
|
|
p = ToKey([]byte{0b0000_0001})
|
|
extendedP = key256.Extend(ToToken(0, 8), p)
|
|
require.Equal([]byte{0b0000_0001, 0b0000_0000, 0b0000_0001}, extendedP.Bytes())
|
|
require.Equal(byte(1), extendedP.Token(0, 8))
|
|
require.Equal(byte(0), extendedP.Token(8, 8))
|
|
require.Equal(byte(1), extendedP.Token(16, 8))
|
|
}
|
|
|
|
func TestKeyBytesNeeded(t *testing.T) {
|
|
type test struct {
|
|
bitLength int
|
|
bytesNeeded int
|
|
}
|
|
|
|
tests := []test{
|
|
{
|
|
bitLength: 7,
|
|
bytesNeeded: 1,
|
|
},
|
|
{
|
|
bitLength: 8,
|
|
bytesNeeded: 1,
|
|
},
|
|
{
|
|
bitLength: 9,
|
|
bytesNeeded: 2,
|
|
},
|
|
{
|
|
bitLength: 0,
|
|
bytesNeeded: 0,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(fmt.Sprintf("bit length %d", tt.bitLength), func(t *testing.T) {
|
|
require := require.New(t)
|
|
require.Equal(tt.bytesNeeded, bytesNeeded(tt.bitLength))
|
|
})
|
|
}
|
|
}
|
|
|
|
func FuzzKeyDoubleExtend_Tokens(f *testing.F) {
|
|
f.Fuzz(func(
|
|
t *testing.T,
|
|
first []byte,
|
|
second []byte,
|
|
tokenByte byte,
|
|
forceFirstOdd bool,
|
|
forceSecondOdd bool,
|
|
) {
|
|
require := require.New(t)
|
|
for _, ts := range validTokenSizes {
|
|
key1 := ToKey(first)
|
|
if forceFirstOdd && key1.length > ts {
|
|
key1 = key1.Take(key1.length - ts)
|
|
}
|
|
key2 := ToKey(second)
|
|
if forceSecondOdd && key2.length > ts {
|
|
key2 = key2.Take(key2.length - ts)
|
|
}
|
|
token := byte(int(tokenByte) % int(tokenSizeToBranchFactor[ts]))
|
|
extendedP := key1.Extend(ToToken(token, ts), key2)
|
|
require.Equal(key1.length+key2.length+ts, extendedP.length)
|
|
firstIndex := 0
|
|
for ; firstIndex < key1.length; firstIndex += ts {
|
|
require.Equal(key1.Token(firstIndex, ts), extendedP.Token(firstIndex, ts))
|
|
}
|
|
require.Equal(token, extendedP.Token(firstIndex, ts))
|
|
firstIndex += ts
|
|
for secondIndex := 0; secondIndex < key2.length; secondIndex += ts {
|
|
require.Equal(key2.Token(secondIndex, ts), extendedP.Token(firstIndex+secondIndex, ts))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func FuzzKeyDoubleExtend_Any(f *testing.F) {
|
|
f.Fuzz(func(
|
|
t *testing.T,
|
|
baseKeyBytes []byte,
|
|
firstKeyBytes []byte,
|
|
secondKeyBytes []byte,
|
|
forceBaseOdd bool,
|
|
forceFirstOdd bool,
|
|
forceSecondOdd bool,
|
|
) {
|
|
require := require.New(t)
|
|
for _, ts := range validTokenSizes {
|
|
baseKey := ToKey(baseKeyBytes)
|
|
if forceBaseOdd && baseKey.length > ts {
|
|
baseKey = baseKey.Take(baseKey.length - ts)
|
|
}
|
|
firstKey := ToKey(firstKeyBytes)
|
|
if forceFirstOdd && firstKey.length > ts {
|
|
firstKey = firstKey.Take(firstKey.length - ts)
|
|
}
|
|
|
|
secondKey := ToKey(secondKeyBytes)
|
|
if forceSecondOdd && secondKey.length > ts {
|
|
secondKey = secondKey.Take(secondKey.length - ts)
|
|
}
|
|
|
|
extendedP := baseKey.Extend(firstKey, secondKey)
|
|
require.Equal(baseKey.length+firstKey.length+secondKey.length, extendedP.length)
|
|
totalIndex := 0
|
|
for baseIndex := 0; baseIndex < baseKey.length; baseIndex += ts {
|
|
require.Equal(baseKey.Token(baseIndex, ts), extendedP.Token(baseIndex, ts))
|
|
}
|
|
totalIndex += baseKey.length
|
|
for firstIndex := 0; firstIndex < firstKey.length; firstIndex += ts {
|
|
require.Equal(firstKey.Token(firstIndex, ts), extendedP.Token(totalIndex+firstIndex, ts))
|
|
}
|
|
totalIndex += firstKey.length
|
|
for secondIndex := 0; secondIndex < secondKey.length; secondIndex += ts {
|
|
require.Equal(secondKey.Token(secondIndex, ts), extendedP.Token(totalIndex+secondIndex, ts))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func FuzzKeySkip(f *testing.F) {
|
|
f.Fuzz(func(
|
|
t *testing.T,
|
|
first []byte,
|
|
tokensToSkip uint,
|
|
) {
|
|
require := require.New(t)
|
|
key1 := ToKey(first)
|
|
for _, ts := range validTokenSizes {
|
|
// need bits to be a multiple of token size
|
|
ubitsToSkip := tokensToSkip * uint(ts)
|
|
if ubitsToSkip >= uint(key1.length) {
|
|
// Skip this token size if no bits to skip
|
|
continue
|
|
}
|
|
bitsToSkip := int(ubitsToSkip)
|
|
key2 := key1.Skip(bitsToSkip)
|
|
require.Equal(key1.length-bitsToSkip, key2.length)
|
|
for i := 0; i < key2.length; i += ts {
|
|
require.Equal(key1.Token(bitsToSkip+i, ts), key2.Token(i, ts))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func FuzzKeyTake(f *testing.F) {
|
|
f.Fuzz(func(
|
|
t *testing.T,
|
|
first []byte,
|
|
uTokensToTake uint,
|
|
) {
|
|
require := require.New(t)
|
|
for _, ts := range validTokenSizes {
|
|
key1 := ToKey(first)
|
|
uBitsToTake := uTokensToTake * uint(ts)
|
|
if uBitsToTake >= uint(key1.length) {
|
|
// Skip this token size if no bits to take
|
|
continue
|
|
}
|
|
bitsToTake := int(uBitsToTake)
|
|
key2 := key1.Take(bitsToTake)
|
|
require.Equal(bitsToTake, key2.length)
|
|
if key2.hasPartialByte() {
|
|
paddingMask := byte(0xFF >> (key2.length % 8))
|
|
require.Zero(key2.value[len(key2.value)-1] & paddingMask)
|
|
}
|
|
for i := 0; i < bitsToTake; i += ts {
|
|
require.Equal(key1.Token(i, ts), key2.Token(i, ts))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestShiftCopy(t *testing.T) {
|
|
type test struct {
|
|
dst []byte
|
|
src []byte
|
|
expected []byte
|
|
shift int
|
|
}
|
|
|
|
tests := []test{
|
|
{
|
|
dst: []byte{},
|
|
src: []byte{},
|
|
expected: []byte{},
|
|
shift: 0,
|
|
},
|
|
{
|
|
dst: []byte{},
|
|
src: []byte{},
|
|
expected: []byte{},
|
|
shift: 1,
|
|
},
|
|
{
|
|
dst: make([]byte, 1),
|
|
src: []byte{0b0000_0001},
|
|
expected: []byte{0b0000_0010},
|
|
shift: 1,
|
|
},
|
|
{
|
|
dst: make([]byte, 1),
|
|
src: []byte{0b0000_0001},
|
|
expected: []byte{0b0000_0100},
|
|
shift: 2,
|
|
},
|
|
{
|
|
dst: make([]byte, 1),
|
|
src: []byte{0b0000_0001},
|
|
expected: []byte{0b1000_0000},
|
|
shift: 7,
|
|
},
|
|
{
|
|
dst: make([]byte, 2),
|
|
src: []byte{0b0000_0001, 0b1000_0001},
|
|
expected: []byte{0b0000_0011, 0b0000_0010},
|
|
shift: 1,
|
|
},
|
|
{
|
|
dst: make([]byte, 1),
|
|
src: []byte{0b0000_0001, 0b1000_0001},
|
|
expected: []byte{0b0000_0011},
|
|
shift: 1,
|
|
},
|
|
{
|
|
dst: make([]byte, 2),
|
|
src: []byte{0b0000_0001, 0b1000_0001},
|
|
expected: []byte{0b1100_0000, 0b1000_0000},
|
|
shift: 7,
|
|
},
|
|
{
|
|
dst: make([]byte, 1),
|
|
src: []byte{0b0000_0001, 0b1000_0001},
|
|
expected: []byte{0b1100_0000},
|
|
shift: 7,
|
|
},
|
|
{
|
|
dst: make([]byte, 2),
|
|
src: []byte{0b0000_0001, 0b1000_0001},
|
|
expected: []byte{0b1000_0001, 0b0000_0000},
|
|
shift: 8,
|
|
},
|
|
{
|
|
dst: make([]byte, 1),
|
|
src: []byte{0b0000_0001, 0b1000_0001},
|
|
expected: []byte{0b1000_0001},
|
|
shift: 8,
|
|
},
|
|
{
|
|
dst: make([]byte, 2),
|
|
src: []byte{0b0000_0001, 0b1000_0001, 0b1111_0101},
|
|
expected: []byte{0b0000_0110, 0b000_0111},
|
|
shift: 2,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(fmt.Sprintf("dst: %v, src: %v", tt.dst, tt.src), func(t *testing.T) {
|
|
shiftCopy(tt.dst, string(tt.src), tt.shift)
|
|
require.Equal(t, tt.expected, tt.dst)
|
|
})
|
|
}
|
|
}
|