1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package tls
16
17 import (
18 "bytes"
19 "encoding/hex"
20 "reflect"
21 "strings"
22 "testing"
23 )
24
25 type testStruct struct {
26 Data []byte `tls:"minlen:2,maxlen:4"`
27 IntVal uint16
28 Other [4]byte
29 Enum Enum `tls:"size:2"`
30 }
31
32 type testVariant struct {
33 Which Enum `tls:"size:1"`
34 Val16 *uint16 `tls:"selector:Which,val:0"`
35 Val32 *uint32 `tls:"selector:Which,val:1"`
36 }
37
38 type testTwoVariants struct {
39 Which Enum `tls:"size:1"`
40 Val16 *uint16 `tls:"selector:Which,val:0"`
41 Val32 *uint32 `tls:"selector:Which,val:1"`
42 Second Enum `tls:"size:1"`
43 Second16 *uint16 `tls:"selector:Second,val:0"`
44 Second32 *uint32 `tls:"selector:Second,val:1"`
45 }
46
47
48 type aliasEnum Enum
49 type testAliasEnum struct {
50 Val aliasEnum `tls:"size:1"`
51 Val16 *uint16 `tls:"selector:Val,val:1"`
52 Val32 *uint32 `tls:"selector:Val,val:2"`
53 }
54
55 type testNonByteSlice struct {
56 Vals []uint16 `tls:"minlen:2,maxlen:6"`
57 }
58
59 type testSliceOfStructs struct {
60 Vals []testVariant `tls:"minlen:0,maxlen:100"`
61 }
62
63 type testInnerType struct {
64 Val []byte `tls:"minlen:0,maxlen:65535"`
65 }
66
67 type testSliceOfSlices struct {
68 Inners []testInnerType `tls:"minlen:0,maxlen:65535"`
69 }
70
71 func TestMarshalUnmarshalRoundTrip(t *testing.T) {
72 thing := testStruct{Data: []byte{0x01, 0x02, 0x03}, IntVal: 42, Other: [4]byte{1, 2, 3, 4}, Enum: 17}
73 data, err := Marshal(thing)
74 if err != nil {
75 t.Fatalf("Failed to Marshal(%+v): %s", thing, err.Error())
76 }
77 var other testStruct
78 rest, err := Unmarshal(data, &other)
79 if err != nil {
80 t.Fatalf("Failed to Unmarshal(%s)", hex.EncodeToString(data))
81 }
82 if len(rest) > 0 {
83 t.Errorf("Data left over after Unmarshal(%s): %s", hex.EncodeToString(data), hex.EncodeToString(rest))
84 }
85 }
86
87 func TestFieldTagToFieldInfo(t *testing.T) {
88 var tests = []struct {
89 tag string
90 want *fieldInfo
91 errstr string
92 }{
93 {"", nil, ""},
94 {"bogus", nil, ""},
95 {"also,bogus", nil, ""},
96 {"also,bogus:99", nil, ""},
97 {"maxval:1xyz", nil, ""},
98 {"maxval:1", &fieldInfo{count: 1, countSet: true}, ""},
99 {"maxval:255", &fieldInfo{count: 1, countSet: true}, ""},
100 {"maxval:256", &fieldInfo{count: 2, countSet: true}, ""},
101 {"maxval:65535", &fieldInfo{count: 2, countSet: true}, ""},
102 {"maxval:65536", &fieldInfo{count: 3, countSet: true}, ""},
103 {"maxval:16777215", &fieldInfo{count: 3, countSet: true}, ""},
104 {"maxval:16777216", &fieldInfo{count: 4, countSet: true}, ""},
105 {"maxval:16777216", &fieldInfo{count: 4, countSet: true}, ""},
106 {"maxval:4294967295", &fieldInfo{count: 4, countSet: true}, ""},
107 {"maxval:4294967296", &fieldInfo{count: 5, countSet: true}, ""},
108 {"maxval:1099511627775", &fieldInfo{count: 5, countSet: true}, ""},
109 {"maxval:1099511627776", &fieldInfo{count: 6, countSet: true}, ""},
110 {"maxval:281474976710655", &fieldInfo{count: 6, countSet: true}, ""},
111 {"maxval:281474976710656", &fieldInfo{count: 7, countSet: true}, ""},
112 {"maxval:72057594037927935", &fieldInfo{count: 7, countSet: true}, ""},
113 {"maxval:72057594037927936", &fieldInfo{count: 8, countSet: true}, ""},
114 {"minlen:1x", nil, ""},
115 {"maxlen:1x", nil, ""},
116 {"maxlen:1", &fieldInfo{count: 1, countSet: true, maxlen: 1}, ""},
117 {"maxlen:255", &fieldInfo{count: 1, countSet: true, maxlen: 255}, ""},
118 {"maxlen:65535", &fieldInfo{count: 2, countSet: true, maxlen: 65535}, ""},
119 {"minlen:65530,maxlen:65535", &fieldInfo{count: 2, countSet: true, minlen: 65530, maxlen: 65535}, ""},
120 {"maxlen:65535,minlen:65530", &fieldInfo{count: 2, countSet: true, minlen: 65530, maxlen: 65535}, ""},
121 {"minlen:65536,maxlen:65535", nil, "inverted"},
122 {"maxlen:16777215", &fieldInfo{count: 3, countSet: true, maxlen: 16777215}, ""},
123 {"maxlen:281474976710655", &fieldInfo{count: 6, countSet: true, maxlen: 281474976710655}, ""},
124 {"maxlen:72057594037927936", &fieldInfo{count: 8, countSet: true, maxlen: 72057594037927936}, ""},
125 {"size:0", nil, "unknown size"},
126 {"size:1", &fieldInfo{count: 1, countSet: true}, ""},
127 {"size:2", &fieldInfo{count: 2, countSet: true}, ""},
128 {"size:3", &fieldInfo{count: 3, countSet: true}, ""},
129 {"size:4", &fieldInfo{count: 4, countSet: true}, ""},
130 {"size:5", &fieldInfo{count: 5, countSet: true}, ""},
131 {"size:6", &fieldInfo{count: 6, countSet: true}, ""},
132 {"size:7", &fieldInfo{count: 7, countSet: true}, ""},
133 {"size:8", &fieldInfo{count: 8, countSet: true}, ""},
134 {"size:9", nil, "too large"},
135 {"size:1x", nil, ""},
136 {"size:1,val:9", nil, "selector value"},
137 {"selector:Bob,val:x9", &fieldInfo{selector: "Bob"}, ""},
138 {"selector:Fred,val:1", &fieldInfo{selector: "Fred", val: 1}, ""},
139 {"val:9,selector:Fred,val:1", &fieldInfo{selector: "Fred", val: 1}, ""},
140 }
141 for _, test := range tests {
142 got, err := fieldTagToFieldInfo(test.tag, "")
143 if test.errstr != "" {
144 if err == nil {
145 t.Errorf("fieldTagToFieldInfo('%v')=%+v,nil; want error %q", test.tag, got, test.errstr)
146 } else if !strings.Contains(err.Error(), test.errstr) {
147 t.Errorf("fieldTagToFieldInfo('%v')=nil,%q; want error %q", test.tag, err.Error(), test.errstr)
148 }
149 continue
150 }
151 if err != nil {
152 t.Errorf("fieldTagToFieldInfo('%v')=nil,%q; want %+v", test.tag, err.Error(), test.want)
153 } else if !reflect.DeepEqual(got, test.want) {
154 t.Errorf("fieldTagToFieldInfo('%v')=%+v,nil; want %+v", test.tag, got, test.want)
155 }
156 }
157 }
158
159
160 func newByte(n byte) *byte { return &n }
161 func newUint8(n uint8) *uint8 { return &n }
162 func newUint16(n uint16) *uint16 { return &n }
163 func newUint24(n Uint24) *Uint24 { return &n }
164 func newUint32(n uint32) *uint32 { return &n }
165 func newUint64(n uint64) *uint64 { return &n }
166 func newInt16(n int16) *int16 { return &n }
167 func newEnum(n Enum) *Enum { return &n }
168
169 func TestUnmarshalMarshalWithParamsRoundTrip(t *testing.T) {
170 var tests = []struct {
171 data string
172 params string
173 item interface{}
174 }{
175 {"00", "", newUint8(0)},
176 {"03", "", newByte(3)},
177 {"0101", "", newUint16(0x0101)},
178 {"010203", "", newUint24(0x010203)},
179 {"000000", "", newUint24(0x00)},
180 {"00000009", "", newUint32(0x09)},
181 {"0000000901020304", "", newUint64(0x0901020304)},
182 {"030405", "", &[3]byte{3, 4, 5}},
183 {"03", "", &[1]byte{3}},
184 {"0001", "size:2", newEnum(1)},
185 {"0100000001", "size:5", newEnum(0x100000001)},
186 {"12", "maxval:18", newEnum(18)},
187
188 {"20", "maxval:18", newEnum(32)},
189 {"020a0b", "minlen:1,maxlen:5", &[]byte{0xa, 0xb}},
190 {"020a0b0101010203040011", "", &testStruct{Data: []byte{0xa, 0xb}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}},
191 {"000102", "", &testVariant{Which: 0, Val16: newUint16(0x0102)}},
192 {"0101020304", "", &testVariant{Which: 1, Val32: newUint32(0x01020304)}},
193 {"0001020104030201", "", &testTwoVariants{Which: 0, Val16: newUint16(0x0102), Second: 1, Second32: newUint32(0x04030201)}},
194 {"06010102020303", "", &testNonByteSlice{Vals: []uint16{0x101, 0x202, 0x303}}},
195 {"00", "", &testSliceOfStructs{Vals: []testVariant{}}},
196 {"080001020101020304", "",
197 &testSliceOfStructs{
198 Vals: []testVariant{
199 {Which: 0, Val16: newUint16(0x0102)},
200 {Which: 1, Val32: newUint32(0x01020304)},
201 },
202 },
203 },
204 {"000a00030102030003040506", "",
205 &testSliceOfSlices{
206 Inners: []testInnerType{
207 {Val: []byte{1, 2, 3}},
208 {Val: []byte{4, 5, 6}},
209 },
210 },
211 },
212 {"011011", "", &testAliasEnum{Val: 1, Val16: newUint16(0x1011)}},
213 {"0403", "", &SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA}},
214 {"04030003010203", "",
215 &DigitallySigned{
216 Algorithm: SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA},
217 Signature: []byte{1, 2, 3},
218 },
219 },
220 }
221 for _, test := range tests {
222 inVal := reflect.ValueOf(test.item).Elem()
223 pv := reflect.New(reflect.TypeOf(test.item).Elem())
224 val := pv.Interface()
225 inData, _ := hex.DecodeString(test.data)
226 if _, err := UnmarshalWithParams(inData, val, test.params); err != nil {
227 t.Errorf("Unmarshal(%s)=nil,%q; want %+v", test.data, err.Error(), inVal)
228 } else if !reflect.DeepEqual(val, test.item) {
229 t.Errorf("Unmarshal(%s)=%+v,nil; want %+v", test.data, reflect.ValueOf(val).Elem(), inVal)
230 }
231
232 if data, err := MarshalWithParams(inVal.Interface(), test.params); err != nil {
233 t.Errorf("Marshal(%+v)=nil,%q; want %s", inVal, err.Error(), test.data)
234 } else if !bytes.Equal(data, inData) {
235 t.Errorf("Marshal(%+v)=%s,nil; want %s", inVal, hex.EncodeToString(data), test.data)
236 }
237 }
238 }
239
240 type testInvalidFieldTag struct {
241 Data []byte `tls:"minlen:3,maxlen:2"`
242 }
243
244 type testDuplicateSelectorVal struct {
245 Which Enum `tls:"size:1"`
246 Val *uint16 `tls:"selector:Which,val:0"`
247 DupVal *uint32 `tls:"selector:Which"`
248 }
249
250 type testMissingSelector struct {
251 Val *uint16 `tls:"selector:Missing,val:0"`
252 }
253
254 type testChoiceNotPointer struct {
255 Which Enum `tls:"size:1"`
256 Val uint16 `tls:"selector:Which,val:0"`
257 }
258
259 type nonEnumAlias uint16
260
261 func newNonEnumAlias(n nonEnumAlias) *nonEnumAlias { return &n }
262
263 func TestUnmarshalWithParamsFailures(t *testing.T) {
264 var tests = []struct {
265 data string
266 params string
267 item interface{}
268 errstr string
269 }{
270 {"", "", newUint8(0), "truncated"},
271 {"0x01", "", newUint16(0x0101), "truncated"},
272 {"0103", "", newUint24(0x010203), "truncated"},
273 {"00", "", newUint24(0x00), "truncated"},
274 {"000009", "", newUint32(0x09), "truncated"},
275 {"00000901020304", "", newUint64(0x0901020304), "truncated"},
276 {"0102", "", newInt16(0x0102), "unsupported type"},
277 {"0607", "", &[3]byte{6, 7, 8}, "truncated array"},
278 {"01010202", "", &[3]uint16{0x101, 0x202}, "unsupported array"},
279 {"01", "", newEnum(1), "no field size"},
280 {"00", "size:2", newEnum(0), "truncated"},
281 {"00", "size:9", newEnum(0), "too large"},
282 {"020a0b", "minlen:4,maxlen:8", &[]byte{0x0a, 0x0b}, "too small"},
283 {"040a0b0c0d", "minlen:1,maxlen:3", &[]byte{0x0a, 0x0b, 0x0c, 0x0d}, "too large"},
284 {"020a0b", "minlen:8,maxlen:6", &[]byte{0x0a, 0x0b}, "inverted"},
285 {"020a", "minlen:0,maxlen:6", &[]byte{0x0a, 0x0b}, "truncated"},
286 {"02", "minlen:0,maxlen:6", &[]byte{0x0a, 0x0b}, "truncated"},
287 {"0001", "minlen:0,maxlen:256", &[]byte{0x0a, 0x0b}, "truncated"},
288 {"020a", "minlen:0", &[]byte{0x0a, 0x0b}, "unknown size"},
289 {"020a", "", &[]byte{0x0a, 0x0b}, "no field size information"},
290 {"020a0b", "", &testInvalidFieldTag{}, "range inverted"},
291 {"020a0b01010102030400", "",
292 &testStruct{Data: []byte{0xa, 0xb}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}, "truncated"},
293 {"010102", "", &testVariant{Which: 1, Val32: newUint32(0x01020304)}, "truncated"},
294 {"092122", "", &testVariant{Which: 0, Val16: newUint16(0x2122)}, "unhandled value for selector"},
295 {"0001020304", "", &testDuplicateSelectorVal{Which: 0, Val: newUint16(0x0102)}, "duplicate selector value"},
296 {"0102", "", &testMissingSelector{Val: newUint16(1)}, "selector not seen"},
297 {"000007", "", &testChoiceNotPointer{Which: 0, Val: 7}, "choice field not a pointer type"},
298 {"05010102020303", "", &testNonByteSlice{Vals: []uint16{0x101, 0x202, 0x303}}, "truncated"},
299 {"0101", "size:2", newNonEnumAlias(0x0102), "unsupported type"},
300 {"0403010203", "",
301 &DigitallySigned{
302 Algorithm: SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA},
303 Signature: []byte{1, 2, 3}}, "truncated"},
304 }
305 for _, test := range tests {
306 pv := reflect.New(reflect.TypeOf(test.item).Elem())
307 val := pv.Interface()
308 in, _ := hex.DecodeString(test.data)
309 if _, err := UnmarshalWithParams(in, val, test.params); err == nil {
310 t.Errorf("Unmarshal(%s)=%+v,nil; want error %q", test.data, reflect.ValueOf(val).Elem(), test.errstr)
311 } else if !strings.Contains(err.Error(), test.errstr) {
312 t.Errorf("Unmarshal(%s)=nil,%q; want error %q", test.data, err.Error(), test.errstr)
313 }
314 }
315 }
316
317 func TestMarshalWithParamsFailures(t *testing.T) {
318 var tests = []struct {
319 item interface{}
320 params string
321 errstr string
322 }{
323 {Uint24(0x1000000), "", "overflow"},
324 {int16(0x0102), "", "unsupported type"},
325 {Enum(1), "", "field tag missing"},
326 {Enum(256), "size:1", "too large"},
327 {Enum(256), "maxval:255", "too large"},
328 {Enum(2), "", "field tag missing"},
329 {Enum(256), "size:9", "too large"},
330 {[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:1,maxlen:3", "too large"},
331 {[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6,maxlen:13", "too small"},
332 {[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6,maxlen:3", "inverted"},
333 {[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6", "unknown size"},
334 {[]byte{0xa, 0xb, 0xc, 0xd}, "", "field tag missing"},
335 {[3]uint16{0x101, 0x202}, "", "unsupported array"},
336 {testInvalidFieldTag{}, "", "inverted"},
337 {testStruct{Data: []byte{0xa}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}, "", "too small"},
338 {testVariant{Which: 0, Val32: newUint32(0x01020304)}, "", "chosen field is nil"},
339 {testVariant{Which: 0, Val16: newUint16(11), Val32: newUint32(0x01020304)}, "", "unchosen field is non-nil"},
340 {testVariant{Which: 3}, "", "unhandled value for selector"},
341 {testMissingSelector{Val: newUint16(1)}, "", "selector not seen"},
342 {testChoiceNotPointer{Which: 0, Val: 7}, "", "choice field not a pointer"},
343 {testDuplicateSelectorVal{Which: 0, Val: newUint16(1)}, "", "duplicate selector value"},
344 {testNonByteSlice{Vals: []uint16{1, 2, 3, 4}}, "", "too large"},
345 {testSliceOfStructs{[]testVariant{{Which: 3}}}, "", "unhandled value for selector"},
346 {nonEnumAlias(0x0102), "", "unsupported type"},
347 }
348 for _, test := range tests {
349 if data, err := MarshalWithParams(test.item, test.params); err == nil {
350 t.Errorf("Marshal(%+v)=%x,nil; want error %q", test.item, data, test.errstr)
351 } else if !strings.Contains(err.Error(), test.errstr) {
352 t.Errorf("Marshal(%+v)=nil,%q; want error %q", test.item, err.Error(), test.errstr)
353 }
354 }
355 }
356
View as plain text