github.com/decred/dcrlnd@v0.7.6/tlv/varint_test.go (about)

     1  package tlv_test
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"math"
     7  	"testing"
     8  
     9  	"github.com/decred/dcrlnd/tlv"
    10  )
    11  
    12  type varIntTest struct {
    13  	Name   string
    14  	Value  uint64
    15  	Bytes  []byte
    16  	ExpErr error
    17  }
    18  
    19  var writeVarIntTests = []varIntTest{
    20  	{
    21  		Name:  "zero",
    22  		Value: 0x00,
    23  		Bytes: []byte{0x00},
    24  	},
    25  	{
    26  		Name:  "one byte high",
    27  		Value: 0xfc,
    28  		Bytes: []byte{0xfc},
    29  	},
    30  	{
    31  		Name:  "two byte low",
    32  		Value: 0xfd,
    33  		Bytes: []byte{0xfd, 0x00, 0xfd},
    34  	},
    35  	{
    36  		Name:  "two byte high",
    37  		Value: 0xffff,
    38  		Bytes: []byte{0xfd, 0xff, 0xff},
    39  	},
    40  	{
    41  		Name:  "four byte low",
    42  		Value: 0x10000,
    43  		Bytes: []byte{0xfe, 0x00, 0x01, 0x00, 0x00},
    44  	},
    45  	{
    46  		Name:  "four byte high",
    47  		Value: 0xffffffff,
    48  		Bytes: []byte{0xfe, 0xff, 0xff, 0xff, 0xff},
    49  	},
    50  	{
    51  		Name:  "eight byte low",
    52  		Value: 0x100000000,
    53  		Bytes: []byte{0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00},
    54  	},
    55  	{
    56  		Name:  "eight byte high",
    57  		Value: math.MaxUint64,
    58  		Bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
    59  	},
    60  }
    61  
    62  // TestWriteVarInt asserts the behavior of tlv.WriteVarInt under various
    63  // positive and negative test cases.
    64  func TestWriteVarInt(t *testing.T) {
    65  	for _, test := range writeVarIntTests {
    66  		t.Run(test.Name, func(t *testing.T) {
    67  			testWriteVarInt(t, test)
    68  		})
    69  	}
    70  }
    71  
    72  func testWriteVarInt(t *testing.T, test varIntTest) {
    73  	var (
    74  		w   bytes.Buffer
    75  		buf [8]byte
    76  	)
    77  	err := tlv.WriteVarInt(&w, test.Value, &buf)
    78  	if err != nil {
    79  		t.Fatalf("unable to encode %d as varint: %v",
    80  			test.Value, err)
    81  	}
    82  
    83  	if !bytes.Equal(w.Bytes(), test.Bytes) {
    84  		t.Fatalf("expected bytes: %v, got %v",
    85  			test.Bytes, w.Bytes())
    86  	}
    87  }
    88  
    89  var readVarIntTests = []varIntTest{
    90  	{
    91  		Name:  "zero",
    92  		Value: 0x00,
    93  		Bytes: []byte{0x00},
    94  	},
    95  	{
    96  		Name:  "one byte high",
    97  		Value: 0xfc,
    98  		Bytes: []byte{0xfc},
    99  	},
   100  	{
   101  		Name:  "two byte low",
   102  		Value: 0xfd,
   103  		Bytes: []byte{0xfd, 0x00, 0xfd},
   104  	},
   105  	{
   106  		Name:  "two byte high",
   107  		Value: 0xffff,
   108  		Bytes: []byte{0xfd, 0xff, 0xff},
   109  	},
   110  	{
   111  		Name:  "four byte low",
   112  		Value: 0x10000,
   113  		Bytes: []byte{0xfe, 0x00, 0x01, 0x00, 0x00},
   114  	},
   115  	{
   116  		Name:  "four byte high",
   117  		Value: 0xffffffff,
   118  		Bytes: []byte{0xfe, 0xff, 0xff, 0xff, 0xff},
   119  	},
   120  	{
   121  		Name:  "eight byte low",
   122  		Value: 0x100000000,
   123  		Bytes: []byte{0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00},
   124  	},
   125  	{
   126  		Name:  "eight byte high",
   127  		Value: math.MaxUint64,
   128  		Bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   129  	},
   130  	{
   131  		Name:   "two byte not canonical",
   132  		Bytes:  []byte{0xfd, 0x00, 0xfc},
   133  		ExpErr: tlv.ErrVarIntNotCanonical,
   134  	},
   135  	{
   136  		Name:   "four byte not canonical",
   137  		Bytes:  []byte{0xfe, 0x00, 0x00, 0xff, 0xff},
   138  		ExpErr: tlv.ErrVarIntNotCanonical,
   139  	},
   140  	{
   141  		Name:   "eight byte not canonical",
   142  		Bytes:  []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
   143  		ExpErr: tlv.ErrVarIntNotCanonical,
   144  	},
   145  	{
   146  		Name:   "two byte short read",
   147  		Bytes:  []byte{0xfd, 0x00},
   148  		ExpErr: io.ErrUnexpectedEOF,
   149  	},
   150  	{
   151  		Name:   "four byte short read",
   152  		Bytes:  []byte{0xfe, 0xff, 0xff},
   153  		ExpErr: io.ErrUnexpectedEOF,
   154  	},
   155  	{
   156  		Name:   "eight byte short read",
   157  		Bytes:  []byte{0xff, 0xff, 0xff, 0xff, 0xff},
   158  		ExpErr: io.ErrUnexpectedEOF,
   159  	},
   160  	{
   161  		Name:   "one byte no read",
   162  		Bytes:  []byte{},
   163  		ExpErr: io.EOF,
   164  	},
   165  	// The following cases are the reason for needing to make a custom
   166  	// version of the varint for the tlv package. For the varint encodings
   167  	// in btcd's wire package these would return io.EOF, since it is
   168  	// actually a composite of two calls to io.ReadFull. In TLV, we need to
   169  	// be able to distinguish whether no bytes were read at all from no
   170  	// Bytes being read on the second read as the latter is not a proper TLV
   171  	// stream. We handle this by returning io.ErrUnexpectedEOF if we
   172  	// encounter io.EOF on any of these secondary reads for larger values.
   173  	{
   174  		Name:   "two byte no read",
   175  		Bytes:  []byte{0xfd},
   176  		ExpErr: io.ErrUnexpectedEOF,
   177  	},
   178  	{
   179  		Name:   "four byte no read",
   180  		Bytes:  []byte{0xfe},
   181  		ExpErr: io.ErrUnexpectedEOF,
   182  	},
   183  	{
   184  		Name:   "eight byte no read",
   185  		Bytes:  []byte{0xff},
   186  		ExpErr: io.ErrUnexpectedEOF,
   187  	},
   188  }
   189  
   190  // TestReadVarInt asserts the behavior of tlv.ReadVarInt under various positive
   191  // and negative test cases.
   192  func TestReadVarInt(t *testing.T) {
   193  	for _, test := range readVarIntTests {
   194  		t.Run(test.Name, func(t *testing.T) {
   195  			testReadVarInt(t, test)
   196  		})
   197  	}
   198  }
   199  
   200  func testReadVarInt(t *testing.T, test varIntTest) {
   201  	var buf [8]byte
   202  	r := bytes.NewReader(test.Bytes)
   203  	val, err := tlv.ReadVarInt(r, &buf)
   204  	if err != nil && err != test.ExpErr {
   205  		t.Fatalf("expected decoding error: %v, got: %v",
   206  			test.ExpErr, err)
   207  	}
   208  
   209  	// If we expected a decoding error, there's no point checking the value.
   210  	if test.ExpErr != nil {
   211  		return
   212  	}
   213  
   214  	if val != test.Value {
   215  		t.Fatalf("expected value: %d, got %d", test.Value, val)
   216  	}
   217  }