2019-09-04 20:46:28 +02:00
|
|
|
package tlv_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2019-10-31 05:20:29 +01:00
|
|
|
"reflect"
|
2019-09-04 20:46:28 +02:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/lightningnetwork/lnd/tlv"
|
2022-04-14 20:43:24 +02:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-09-04 20:46:28 +02:00
|
|
|
)
|
|
|
|
|
2019-10-31 05:20:29 +01:00
|
|
|
type parsedTypeTest struct {
|
2019-11-10 12:06:49 +01:00
|
|
|
name string
|
|
|
|
encode []tlv.Type
|
|
|
|
decode []tlv.Type
|
2019-11-19 12:05:20 +01:00
|
|
|
expParsedTypes tlv.TypeMap
|
2019-10-31 05:20:29 +01:00
|
|
|
}
|
|
|
|
|
2019-09-04 20:46:28 +02:00
|
|
|
// TestParsedTypes asserts that a Stream will properly return the set of types
|
|
|
|
// that it encounters when the type is known-and-decoded or unknown-and-ignored.
|
|
|
|
func TestParsedTypes(t *testing.T) {
|
|
|
|
const (
|
2019-11-10 12:06:49 +01:00
|
|
|
knownType = 1
|
|
|
|
unknownType = 3
|
|
|
|
secondKnownType = 4
|
2019-09-04 20:46:28 +02:00
|
|
|
)
|
|
|
|
|
2019-10-31 05:20:29 +01:00
|
|
|
tests := []parsedTypeTest{
|
|
|
|
{
|
2019-11-10 12:06:49 +01:00
|
|
|
name: "known and unknown",
|
2019-10-31 05:20:29 +01:00
|
|
|
encode: []tlv.Type{knownType, unknownType},
|
|
|
|
decode: []tlv.Type{knownType},
|
2019-11-19 12:05:20 +01:00
|
|
|
expParsedTypes: tlv.TypeMap{
|
|
|
|
unknownType: []byte{0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
|
knownType: nil,
|
2019-11-10 12:06:49 +01:00
|
|
|
},
|
2019-10-31 05:20:29 +01:00
|
|
|
},
|
|
|
|
{
|
2019-11-10 12:06:49 +01:00
|
|
|
name: "known and missing known",
|
|
|
|
encode: []tlv.Type{knownType},
|
|
|
|
decode: []tlv.Type{knownType, secondKnownType},
|
2019-11-19 12:05:20 +01:00
|
|
|
expParsedTypes: tlv.TypeMap{
|
|
|
|
knownType: nil,
|
2019-11-10 12:06:49 +01:00
|
|
|
},
|
2019-10-31 05:20:29 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
test := test
|
|
|
|
t.Run(test.name, func(t *testing.T) {
|
|
|
|
testParsedTypes(t, test)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testParsedTypes(t *testing.T, test parsedTypeTest) {
|
|
|
|
encRecords := make([]tlv.Record, 0, len(test.encode))
|
|
|
|
for _, typ := range test.encode {
|
|
|
|
encRecords = append(
|
|
|
|
encRecords, tlv.MakePrimitiveRecord(typ, new(uint64)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
decRecords := make([]tlv.Record, 0, len(test.decode))
|
|
|
|
for _, typ := range test.decode {
|
|
|
|
decRecords = append(
|
|
|
|
decRecords, tlv.MakePrimitiveRecord(typ, new(uint64)),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct a stream that will encode the test's set of types.
|
|
|
|
encStream := tlv.MustNewStream(encRecords...)
|
2019-09-04 20:46:28 +02:00
|
|
|
|
|
|
|
var b bytes.Buffer
|
|
|
|
if err := encStream.Encode(&b); err != nil {
|
|
|
|
t.Fatalf("unable to encode stream: %v", err)
|
|
|
|
}
|
|
|
|
|
2019-10-31 05:20:29 +01:00
|
|
|
// Create a stream that will parse a subset of the test's types.
|
|
|
|
decStream := tlv.MustNewStream(decRecords...)
|
2019-09-04 20:46:28 +02:00
|
|
|
|
|
|
|
parsedTypes, err := decStream.DecodeWithParsedTypes(
|
|
|
|
bytes.NewReader(b.Bytes()),
|
|
|
|
)
|
2019-11-10 12:06:49 +01:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error decoding: %v", err)
|
2019-09-04 20:46:28 +02:00
|
|
|
}
|
2019-11-10 12:06:49 +01:00
|
|
|
if !reflect.DeepEqual(parsedTypes, test.expParsedTypes) {
|
|
|
|
t.Fatalf("error mismatch on parsed types")
|
2019-09-04 20:46:28 +02:00
|
|
|
}
|
|
|
|
}
|
2022-04-14 20:43:24 +02:00
|
|
|
|
|
|
|
var (
|
|
|
|
smallValue = 1
|
|
|
|
smallValueBytes = []byte{
|
|
|
|
// uint32 tlv, value uses 1 byte.
|
|
|
|
0xa, 0x1, 0x1,
|
|
|
|
// uint64 tlv, value uses 1 byte.
|
|
|
|
0xb, 0x1, 0x1,
|
|
|
|
}
|
|
|
|
|
|
|
|
medianValue = 255
|
|
|
|
medianValueBytes = []byte{
|
|
|
|
// uint32 tlv, value uses 3 byte.
|
|
|
|
0xa, 0x3, 0xfd, 0x0, 0xff,
|
|
|
|
// uint64 tlv, value uses 3 byte.
|
|
|
|
0xb, 0x3, 0xfd, 0x0, 0xff,
|
|
|
|
}
|
|
|
|
|
|
|
|
largeValue = 65536
|
|
|
|
largeValueBytes = []byte{
|
|
|
|
// uint32 tlv, value uses 5 byte.
|
|
|
|
0xa, 0x5, 0xfe, 0x0, 0x1, 0x0, 0x0,
|
|
|
|
// uint64 tlv, value uses 5 byte.
|
|
|
|
0xb, 0x5, 0xfe, 0x0, 0x1, 0x0, 0x0,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// TestEncodeBigSizeFormatTlvStream tests that the bigsize encoder works as
|
|
|
|
// expected.
|
|
|
|
func TestEncodeBigSizeFormatTlvStream(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
value int
|
|
|
|
expectedBytes []byte
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
// Test encode 1, which saves us space.
|
|
|
|
name: "encode small value",
|
|
|
|
value: smallValue,
|
|
|
|
expectedBytes: smallValueBytes,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Test encode 255, which still saves us space.
|
|
|
|
name: "encode median value",
|
|
|
|
value: medianValue,
|
|
|
|
expectedBytes: medianValueBytes,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Test encode 65536, which takes more space to encode
|
|
|
|
// an uint32.
|
|
|
|
name: "encode large value",
|
|
|
|
value: largeValue,
|
|
|
|
expectedBytes: largeValueBytes,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
tc := tc
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
testUint32 := uint32(tc.value)
|
|
|
|
testUint64 := uint64(tc.value)
|
|
|
|
ts := makeBigSizeFormatTlvStream(
|
|
|
|
t, &testUint32, &testUint64,
|
|
|
|
)
|
|
|
|
|
|
|
|
// Encode the tlv stream.
|
|
|
|
buf := bytes.NewBuffer([]byte{})
|
|
|
|
require.NoError(t, ts.Encode(buf))
|
|
|
|
|
|
|
|
// Check the bytes are written as expected.
|
|
|
|
require.Equal(t, tc.expectedBytes, buf.Bytes())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestDecodeBigSizeFormatTlvStream tests that the bigsize decoder works as
|
|
|
|
// expected.
|
|
|
|
func TestDecodeBigSizeFormatTlvStream(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
bytes []byte
|
|
|
|
expectedValue int
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
// Test decode 1.
|
|
|
|
name: "decode small value",
|
|
|
|
bytes: []byte{
|
|
|
|
// uint32 tlv, value uses 1 byte.
|
|
|
|
0xa, 0x1, 0x1,
|
|
|
|
// uint64 tlv, value uses 1 byte.
|
|
|
|
0xb, 0x1, 0x1,
|
|
|
|
},
|
|
|
|
expectedValue: smallValue,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Test decode 255.
|
|
|
|
name: "decode median value",
|
|
|
|
bytes: []byte{
|
|
|
|
// uint32 tlv, value uses 3 byte.
|
|
|
|
0xa, 0x3, 0xfd, 0x0, 0xff,
|
|
|
|
// uint64 tlv, value uses 3 byte.
|
|
|
|
0xb, 0x3, 0xfd, 0x0, 0xff,
|
|
|
|
},
|
|
|
|
expectedValue: medianValue,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// Test decode 65536.
|
|
|
|
name: "decode value 65536",
|
|
|
|
bytes: []byte{
|
|
|
|
// uint32 tlv, value uses 5 byte.
|
|
|
|
0xa, 0x5, 0xfe, 0x0, 0x1, 0x0, 0x0,
|
|
|
|
// uint64 tlv, value uses 5 byte.
|
|
|
|
0xb, 0x5, 0xfe, 0x0, 0x1, 0x0, 0x0,
|
|
|
|
},
|
|
|
|
expectedValue: largeValue,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
tc := tc
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
var (
|
|
|
|
testUint32 uint32
|
|
|
|
testUint64 uint64
|
|
|
|
)
|
|
|
|
ts := makeBigSizeFormatTlvStream(
|
|
|
|
t, &testUint32, &testUint64,
|
|
|
|
)
|
|
|
|
|
|
|
|
// Decode the tlv stream.
|
|
|
|
buf := bytes.NewBuffer(tc.bytes)
|
|
|
|
require.NoError(t, ts.Decode(buf))
|
|
|
|
|
|
|
|
// Check the values are written as expected.
|
|
|
|
require.EqualValues(t, tc.expectedValue, testUint32)
|
|
|
|
require.EqualValues(t, tc.expectedValue, testUint64)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeBigSizeFormatTlvStream(t *testing.T, vUint32 *uint32,
|
|
|
|
vUint64 *uint64) *tlv.Stream {
|
|
|
|
|
|
|
|
const (
|
|
|
|
typeUint32 tlv.Type = 10
|
|
|
|
typeUint64 tlv.Type = 11
|
|
|
|
)
|
|
|
|
|
|
|
|
// Create a dummy tlv stream for testing.
|
|
|
|
ts, err := tlv.NewStream(
|
|
|
|
tlv.MakeBigSizeRecord(typeUint32, vUint32),
|
|
|
|
tlv.MakeBigSizeRecord(typeUint64, vUint64),
|
|
|
|
)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return ts
|
|
|
|
}
|