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 }