1// Copyright 2017 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package cryptobyte
6
7import (
8	"bytes"
9	"errors"
10	"fmt"
11	"testing"
12)
13
14func builderBytesEq(b *Builder, want ...byte) error {
15	got := b.BytesOrPanic()
16	if !bytes.Equal(got, want) {
17		return fmt.Errorf("Bytes() = %v, want %v", got, want)
18	}
19	return nil
20}
21
22func TestContinuationError(t *testing.T) {
23	const errorStr = "TestContinuationError"
24	var b Builder
25	b.AddUint8LengthPrefixed(func(b *Builder) {
26		b.AddUint8(1)
27		panic(BuildError{Err: errors.New(errorStr)})
28	})
29
30	ret, err := b.Bytes()
31	if ret != nil {
32		t.Error("expected nil result")
33	}
34	if err == nil {
35		t.Fatal("unexpected nil error")
36	}
37	if s := err.Error(); s != errorStr {
38		t.Errorf("expected error %q, got %v", errorStr, s)
39	}
40}
41
42func TestContinuationNonError(t *testing.T) {
43	defer func() {
44		recover()
45	}()
46
47	var b Builder
48	b.AddUint8LengthPrefixed(func(b *Builder) {
49		b.AddUint8(1)
50		panic(1)
51	})
52
53	t.Error("Builder did not panic")
54}
55
56func TestGeneratedPanic(t *testing.T) {
57	defer func() {
58		recover()
59	}()
60
61	var b Builder
62	b.AddUint8LengthPrefixed(func(b *Builder) {
63		var p *byte
64		*p = 0
65	})
66
67	t.Error("Builder did not panic")
68}
69
70func TestBytes(t *testing.T) {
71	var b Builder
72	v := []byte("foobarbaz")
73	b.AddBytes(v[0:3])
74	b.AddBytes(v[3:4])
75	b.AddBytes(v[4:9])
76	if err := builderBytesEq(&b, v...); err != nil {
77		t.Error(err)
78	}
79	s := String(b.BytesOrPanic())
80	for _, w := range []string{"foo", "bar", "baz"} {
81		var got []byte
82		if !s.ReadBytes(&got, 3) {
83			t.Errorf("ReadBytes() = false, want true (w = %v)", w)
84		}
85		want := []byte(w)
86		if !bytes.Equal(got, want) {
87			t.Errorf("ReadBytes(): got = %v, want %v", got, want)
88		}
89	}
90	if len(s) != 0 {
91		t.Errorf("len(s) = %d, want 0", len(s))
92	}
93}
94
95func TestUint8(t *testing.T) {
96	var b Builder
97	b.AddUint8(42)
98	if err := builderBytesEq(&b, 42); err != nil {
99		t.Error(err)
100	}
101
102	var s String = b.BytesOrPanic()
103	var v uint8
104	if !s.ReadUint8(&v) {
105		t.Error("ReadUint8() = false, want true")
106	}
107	if v != 42 {
108		t.Errorf("v = %d, want 42", v)
109	}
110	if len(s) != 0 {
111		t.Errorf("len(s) = %d, want 0", len(s))
112	}
113}
114
115func TestUint16(t *testing.T) {
116	var b Builder
117	b.AddUint16(65534)
118	if err := builderBytesEq(&b, 255, 254); err != nil {
119		t.Error(err)
120	}
121	var s String = b.BytesOrPanic()
122	var v uint16
123	if !s.ReadUint16(&v) {
124		t.Error("ReadUint16() == false, want true")
125	}
126	if v != 65534 {
127		t.Errorf("v = %d, want 65534", v)
128	}
129	if len(s) != 0 {
130		t.Errorf("len(s) = %d, want 0", len(s))
131	}
132}
133
134func TestUint24(t *testing.T) {
135	var b Builder
136	b.AddUint24(0xfffefd)
137	if err := builderBytesEq(&b, 255, 254, 253); err != nil {
138		t.Error(err)
139	}
140
141	var s String = b.BytesOrPanic()
142	var v uint32
143	if !s.ReadUint24(&v) {
144		t.Error("ReadUint8() = false, want true")
145	}
146	if v != 0xfffefd {
147		t.Errorf("v = %d, want fffefd", v)
148	}
149	if len(s) != 0 {
150		t.Errorf("len(s) = %d, want 0", len(s))
151	}
152}
153
154func TestUint24Truncation(t *testing.T) {
155	var b Builder
156	b.AddUint24(0x10111213)
157	if err := builderBytesEq(&b, 0x11, 0x12, 0x13); err != nil {
158		t.Error(err)
159	}
160}
161
162func TestUint32(t *testing.T) {
163	var b Builder
164	b.AddUint32(0xfffefdfc)
165	if err := builderBytesEq(&b, 255, 254, 253, 252); err != nil {
166		t.Error(err)
167	}
168
169	var s String = b.BytesOrPanic()
170	var v uint32
171	if !s.ReadUint32(&v) {
172		t.Error("ReadUint8() = false, want true")
173	}
174	if v != 0xfffefdfc {
175		t.Errorf("v = %x, want fffefdfc", v)
176	}
177	if len(s) != 0 {
178		t.Errorf("len(s) = %d, want 0", len(s))
179	}
180}
181
182func TestUMultiple(t *testing.T) {
183	var b Builder
184	b.AddUint8(23)
185	b.AddUint32(0xfffefdfc)
186	b.AddUint16(42)
187	if err := builderBytesEq(&b, 23, 255, 254, 253, 252, 0, 42); err != nil {
188		t.Error(err)
189	}
190
191	var s String = b.BytesOrPanic()
192	var (
193		x uint8
194		y uint32
195		z uint16
196	)
197	if !s.ReadUint8(&x) || !s.ReadUint32(&y) || !s.ReadUint16(&z) {
198		t.Error("ReadUint8() = false, want true")
199	}
200	if x != 23 || y != 0xfffefdfc || z != 42 {
201		t.Errorf("x, y, z = %d, %d, %d; want 23, 4294901244, 5", x, y, z)
202	}
203	if len(s) != 0 {
204		t.Errorf("len(s) = %d, want 0", len(s))
205	}
206}
207
208func TestUint8LengthPrefixedSimple(t *testing.T) {
209	var b Builder
210	b.AddUint8LengthPrefixed(func(c *Builder) {
211		c.AddUint8(23)
212		c.AddUint8(42)
213	})
214	if err := builderBytesEq(&b, 2, 23, 42); err != nil {
215		t.Error(err)
216	}
217
218	var base, child String = b.BytesOrPanic(), nil
219	var x, y uint8
220	if !base.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) ||
221		!child.ReadUint8(&y) {
222		t.Error("parsing failed")
223	}
224	if x != 23 || y != 42 {
225		t.Errorf("want x, y == 23, 42; got %d, %d", x, y)
226	}
227	if len(base) != 0 {
228		t.Errorf("len(base) = %d, want 0", len(base))
229	}
230	if len(child) != 0 {
231		t.Errorf("len(child) = %d, want 0", len(child))
232	}
233}
234
235func TestUint8LengthPrefixedMulti(t *testing.T) {
236	var b Builder
237	b.AddUint8LengthPrefixed(func(c *Builder) {
238		c.AddUint8(23)
239		c.AddUint8(42)
240	})
241	b.AddUint8(5)
242	b.AddUint8LengthPrefixed(func(c *Builder) {
243		c.AddUint8(123)
244		c.AddUint8(234)
245	})
246	if err := builderBytesEq(&b, 2, 23, 42, 5, 2, 123, 234); err != nil {
247		t.Error(err)
248	}
249
250	var s, child String = b.BytesOrPanic(), nil
251	var u, v, w, x, y uint8
252	if !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&u) || !child.ReadUint8(&v) ||
253		!s.ReadUint8(&w) || !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || !child.ReadUint8(&y) {
254		t.Error("parsing failed")
255	}
256	if u != 23 || v != 42 || w != 5 || x != 123 || y != 234 {
257		t.Errorf("u, v, w, x, y = %d, %d, %d, %d, %d; want 23, 42, 5, 123, 234",
258			u, v, w, x, y)
259	}
260	if len(s) != 0 {
261		t.Errorf("len(s) = %d, want 0", len(s))
262	}
263	if len(child) != 0 {
264		t.Errorf("len(child) = %d, want 0", len(child))
265	}
266}
267
268func TestUint8LengthPrefixedNested(t *testing.T) {
269	var b Builder
270	b.AddUint8LengthPrefixed(func(c *Builder) {
271		c.AddUint8(5)
272		c.AddUint8LengthPrefixed(func(d *Builder) {
273			d.AddUint8(23)
274			d.AddUint8(42)
275		})
276		c.AddUint8(123)
277	})
278	if err := builderBytesEq(&b, 5, 5, 2, 23, 42, 123); err != nil {
279		t.Error(err)
280	}
281
282	var base, child1, child2 String = b.BytesOrPanic(), nil, nil
283	var u, v, w, x uint8
284	if !base.ReadUint8LengthPrefixed(&child1) {
285		t.Error("parsing base failed")
286	}
287	if !child1.ReadUint8(&u) || !child1.ReadUint8LengthPrefixed(&child2) || !child1.ReadUint8(&x) {
288		t.Error("parsing child1 failed")
289	}
290	if !child2.ReadUint8(&v) || !child2.ReadUint8(&w) {
291		t.Error("parsing child2 failed")
292	}
293	if u != 5 || v != 23 || w != 42 || x != 123 {
294		t.Errorf("u, v, w, x = %d, %d, %d, %d, want 5, 23, 42, 123",
295			u, v, w, x)
296	}
297	if len(base) != 0 {
298		t.Errorf("len(base) = %d, want 0", len(base))
299	}
300	if len(child1) != 0 {
301		t.Errorf("len(child1) = %d, want 0", len(child1))
302	}
303	if len(base) != 0 {
304		t.Errorf("len(child2) = %d, want 0", len(child2))
305	}
306}
307
308func TestPreallocatedBuffer(t *testing.T) {
309	var buf [5]byte
310	b := NewBuilder(buf[0:0])
311	b.AddUint8(1)
312	b.AddUint8LengthPrefixed(func(c *Builder) {
313		c.AddUint8(3)
314		c.AddUint8(4)
315	})
316	b.AddUint16(1286) // Outgrow buf by one byte.
317	want := []byte{1, 2, 3, 4, 0}
318	if !bytes.Equal(buf[:], want) {
319		t.Errorf("buf = %v want %v", buf, want)
320	}
321	if err := builderBytesEq(b, 1, 2, 3, 4, 5, 6); err != nil {
322		t.Error(err)
323	}
324}
325
326func TestWriteWithPendingChild(t *testing.T) {
327	var b Builder
328	b.AddUint8LengthPrefixed(func(c *Builder) {
329		c.AddUint8LengthPrefixed(func(d *Builder) {
330			func() {
331				defer func() {
332					if recover() == nil {
333						t.Errorf("recover() = nil, want error; c.AddUint8() did not panic")
334					}
335				}()
336				c.AddUint8(2) // panics
337			}()
338
339			defer func() {
340				if recover() == nil {
341					t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
342				}
343			}()
344			b.AddUint8(2) // panics
345		})
346
347		defer func() {
348			if recover() == nil {
349				t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
350			}
351		}()
352		b.AddUint8(2) // panics
353	})
354}
355
356func TestSetError(t *testing.T) {
357	const errorStr = "TestSetError"
358	var b Builder
359	b.SetError(errors.New(errorStr))
360
361	ret, err := b.Bytes()
362	if ret != nil {
363		t.Error("expected nil result")
364	}
365	if err == nil {
366		t.Fatal("unexpected nil error")
367	}
368	if s := err.Error(); s != errorStr {
369		t.Errorf("expected error %q, got %v", errorStr, s)
370	}
371}
372
373func TestUnwrite(t *testing.T) {
374	var b Builder
375	b.AddBytes([]byte{1, 2, 3, 4, 5})
376	b.Unwrite(2)
377	if err := builderBytesEq(&b, 1, 2, 3); err != nil {
378		t.Error(err)
379	}
380
381	func() {
382		defer func() {
383			if recover() == nil {
384				t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
385			}
386		}()
387		b.Unwrite(4) // panics
388	}()
389
390	b = Builder{}
391	b.AddBytes([]byte{1, 2, 3, 4, 5})
392	b.AddUint8LengthPrefixed(func(b *Builder) {
393		b.AddBytes([]byte{1, 2, 3, 4, 5})
394
395		defer func() {
396			if recover() == nil {
397				t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
398			}
399		}()
400		b.Unwrite(6) // panics
401	})
402
403	b = Builder{}
404	b.AddBytes([]byte{1, 2, 3, 4, 5})
405	b.AddUint8LengthPrefixed(func(c *Builder) {
406		defer func() {
407			if recover() == nil {
408				t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
409			}
410		}()
411		b.Unwrite(2) // panics (attempted unwrite while child is pending)
412	})
413}
414
415func TestFixedBuilderLengthPrefixed(t *testing.T) {
416	bufCap := 10
417	inner := bytes.Repeat([]byte{0xff}, bufCap-2)
418	buf := make([]byte, 0, bufCap)
419	b := NewFixedBuilder(buf)
420	b.AddUint16LengthPrefixed(func(b *Builder) {
421		b.AddBytes(inner)
422	})
423	if got := b.BytesOrPanic(); len(got) != bufCap {
424		t.Errorf("Expected output length to be %d, got %d", bufCap, len(got))
425	}
426}
427
428func TestFixedBuilderPanicReallocate(t *testing.T) {
429	defer func() {
430		recover()
431	}()
432
433	b := NewFixedBuilder(make([]byte, 0, 10))
434	b1 := NewFixedBuilder(make([]byte, 0, 10))
435	b.AddUint16LengthPrefixed(func(b *Builder) {
436		*b = *b1
437	})
438
439	t.Error("Builder did not panic")
440}
441
442// ASN.1
443
444func TestASN1Int64(t *testing.T) {
445	tests := []struct {
446		in   int64
447		want []byte
448	}{
449		{-0x800000, []byte{2, 3, 128, 0, 0}},
450		{-256, []byte{2, 2, 255, 0}},
451		{-129, []byte{2, 2, 255, 127}},
452		{-128, []byte{2, 1, 128}},
453		{-1, []byte{2, 1, 255}},
454		{0, []byte{2, 1, 0}},
455		{1, []byte{2, 1, 1}},
456		{2, []byte{2, 1, 2}},
457		{127, []byte{2, 1, 127}},
458		{128, []byte{2, 2, 0, 128}},
459		{256, []byte{2, 2, 1, 0}},
460		{0x800000, []byte{2, 4, 0, 128, 0, 0}},
461	}
462	for i, tt := range tests {
463		var b Builder
464		b.AddASN1Int64(tt.in)
465		if err := builderBytesEq(&b, tt.want...); err != nil {
466			t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
467		}
468
469		var n int64
470		s := String(b.BytesOrPanic())
471		ok := s.ReadASN1Integer(&n)
472		if !ok || n != tt.in {
473			t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
474				ok, n, tt.in, i)
475		}
476		if len(s) != 0 {
477			t.Errorf("len(s) = %d, want 0", len(s))
478		}
479	}
480}
481
482func TestASN1Uint64(t *testing.T) {
483	tests := []struct {
484		in   uint64
485		want []byte
486	}{
487		{0, []byte{2, 1, 0}},
488		{1, []byte{2, 1, 1}},
489		{2, []byte{2, 1, 2}},
490		{127, []byte{2, 1, 127}},
491		{128, []byte{2, 2, 0, 128}},
492		{256, []byte{2, 2, 1, 0}},
493		{0x800000, []byte{2, 4, 0, 128, 0, 0}},
494		{0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}},
495		{0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}},
496		{0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}},
497	}
498	for i, tt := range tests {
499		var b Builder
500		b.AddASN1Uint64(tt.in)
501		if err := builderBytesEq(&b, tt.want...); err != nil {
502			t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
503		}
504
505		var n uint64
506		s := String(b.BytesOrPanic())
507		ok := s.ReadASN1Integer(&n)
508		if !ok || n != tt.in {
509			t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
510				ok, n, tt.in, i)
511		}
512		if len(s) != 0 {
513			t.Errorf("len(s) = %d, want 0", len(s))
514		}
515	}
516}
517