You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
4.6 KiB
217 lines
4.6 KiB
package tlv_test |
|
|
|
import ( |
|
"bytes" |
|
"io" |
|
"math" |
|
"testing" |
|
|
|
"github.com/lightningnetwork/lnd/tlv" |
|
) |
|
|
|
type varIntTest struct { |
|
Name string |
|
Value uint64 |
|
Bytes []byte |
|
ExpErr error |
|
} |
|
|
|
var writeVarIntTests = []varIntTest{ |
|
{ |
|
Name: "zero", |
|
Value: 0x00, |
|
Bytes: []byte{0x00}, |
|
}, |
|
{ |
|
Name: "one byte high", |
|
Value: 0xfc, |
|
Bytes: []byte{0xfc}, |
|
}, |
|
{ |
|
Name: "two byte low", |
|
Value: 0xfd, |
|
Bytes: []byte{0xfd, 0x00, 0xfd}, |
|
}, |
|
{ |
|
Name: "two byte high", |
|
Value: 0xffff, |
|
Bytes: []byte{0xfd, 0xff, 0xff}, |
|
}, |
|
{ |
|
Name: "four byte low", |
|
Value: 0x10000, |
|
Bytes: []byte{0xfe, 0x00, 0x01, 0x00, 0x00}, |
|
}, |
|
{ |
|
Name: "four byte high", |
|
Value: 0xffffffff, |
|
Bytes: []byte{0xfe, 0xff, 0xff, 0xff, 0xff}, |
|
}, |
|
{ |
|
Name: "eight byte low", |
|
Value: 0x100000000, |
|
Bytes: []byte{0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}, |
|
}, |
|
{ |
|
Name: "eight byte high", |
|
Value: math.MaxUint64, |
|
Bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, |
|
}, |
|
} |
|
|
|
// TestWriteVarInt asserts the behavior of tlv.WriteVarInt under various |
|
// positive and negative test cases. |
|
func TestWriteVarInt(t *testing.T) { |
|
for _, test := range writeVarIntTests { |
|
t.Run(test.Name, func(t *testing.T) { |
|
testWriteVarInt(t, test) |
|
}) |
|
} |
|
} |
|
|
|
func testWriteVarInt(t *testing.T, test varIntTest) { |
|
var ( |
|
w bytes.Buffer |
|
buf [8]byte |
|
) |
|
err := tlv.WriteVarInt(&w, test.Value, &buf) |
|
if err != nil { |
|
t.Fatalf("unable to encode %d as varint: %v", |
|
test.Value, err) |
|
} |
|
|
|
if !bytes.Equal(w.Bytes(), test.Bytes) { |
|
t.Fatalf("expected bytes: %v, got %v", |
|
test.Bytes, w.Bytes()) |
|
} |
|
} |
|
|
|
var readVarIntTests = []varIntTest{ |
|
{ |
|
Name: "zero", |
|
Value: 0x00, |
|
Bytes: []byte{0x00}, |
|
}, |
|
{ |
|
Name: "one byte high", |
|
Value: 0xfc, |
|
Bytes: []byte{0xfc}, |
|
}, |
|
{ |
|
Name: "two byte low", |
|
Value: 0xfd, |
|
Bytes: []byte{0xfd, 0x00, 0xfd}, |
|
}, |
|
{ |
|
Name: "two byte high", |
|
Value: 0xffff, |
|
Bytes: []byte{0xfd, 0xff, 0xff}, |
|
}, |
|
{ |
|
Name: "four byte low", |
|
Value: 0x10000, |
|
Bytes: []byte{0xfe, 0x00, 0x01, 0x00, 0x00}, |
|
}, |
|
{ |
|
Name: "four byte high", |
|
Value: 0xffffffff, |
|
Bytes: []byte{0xfe, 0xff, 0xff, 0xff, 0xff}, |
|
}, |
|
{ |
|
Name: "eight byte low", |
|
Value: 0x100000000, |
|
Bytes: []byte{0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}, |
|
}, |
|
{ |
|
Name: "eight byte high", |
|
Value: math.MaxUint64, |
|
Bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, |
|
}, |
|
{ |
|
Name: "two byte not canonical", |
|
Bytes: []byte{0xfd, 0x00, 0xfc}, |
|
ExpErr: tlv.ErrVarIntNotCanonical, |
|
}, |
|
{ |
|
Name: "four byte not canonical", |
|
Bytes: []byte{0xfe, 0x00, 0x00, 0xff, 0xff}, |
|
ExpErr: tlv.ErrVarIntNotCanonical, |
|
}, |
|
{ |
|
Name: "eight byte not canonical", |
|
Bytes: []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, |
|
ExpErr: tlv.ErrVarIntNotCanonical, |
|
}, |
|
{ |
|
Name: "two byte short read", |
|
Bytes: []byte{0xfd, 0x00}, |
|
ExpErr: io.ErrUnexpectedEOF, |
|
}, |
|
{ |
|
Name: "four byte short read", |
|
Bytes: []byte{0xfe, 0xff, 0xff}, |
|
ExpErr: io.ErrUnexpectedEOF, |
|
}, |
|
{ |
|
Name: "eight byte short read", |
|
Bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff}, |
|
ExpErr: io.ErrUnexpectedEOF, |
|
}, |
|
{ |
|
Name: "one byte no read", |
|
Bytes: []byte{}, |
|
ExpErr: io.EOF, |
|
}, |
|
// The following cases are the reason for needing to make a custom |
|
// version of the varint for the tlv package. For the varint encodings |
|
// in btcd's wire package these would return io.EOF, since it is |
|
// actually a composite of two calls to io.ReadFull. In TLV, we need to |
|
// be able to distinguish whether no bytes were read at all from no |
|
// Bytes being read on the second read as the latter is not a proper TLV |
|
// stream. We handle this by returning io.ErrUnexpectedEOF if we |
|
// encounter io.EOF on any of these secondary reads for larger values. |
|
{ |
|
Name: "two byte no read", |
|
Bytes: []byte{0xfd}, |
|
ExpErr: io.ErrUnexpectedEOF, |
|
}, |
|
{ |
|
Name: "four byte no read", |
|
Bytes: []byte{0xfe}, |
|
ExpErr: io.ErrUnexpectedEOF, |
|
}, |
|
{ |
|
Name: "eight byte no read", |
|
Bytes: []byte{0xff}, |
|
ExpErr: io.ErrUnexpectedEOF, |
|
}, |
|
} |
|
|
|
// TestReadVarInt asserts the behavior of tlv.ReadVarInt under various positive |
|
// and negative test cases. |
|
func TestReadVarInt(t *testing.T) { |
|
for _, test := range readVarIntTests { |
|
t.Run(test.Name, func(t *testing.T) { |
|
testReadVarInt(t, test) |
|
}) |
|
} |
|
} |
|
|
|
func testReadVarInt(t *testing.T, test varIntTest) { |
|
var buf [8]byte |
|
r := bytes.NewReader(test.Bytes) |
|
val, err := tlv.ReadVarInt(r, &buf) |
|
if err != nil && err != test.ExpErr { |
|
t.Fatalf("expected decoding error: %v, got: %v", |
|
test.ExpErr, err) |
|
} |
|
|
|
// If we expected a decoding error, there's no point checking the value. |
|
if test.ExpErr != nil { |
|
return |
|
} |
|
|
|
if val != test.Value { |
|
t.Fatalf("expected value: %d, got %d", test.Value, val) |
|
} |
|
}
|
|
|