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			defer func() {
331				if recover() == nil {
332					t.Errorf("recover() = nil, want error; c.AddUint8() did not panic")
333				}
334			}()
335			c.AddUint8(2) // panics
336
337			defer func() {
338				if recover() == nil {
339					t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
340				}
341			}()
342			b.AddUint8(2) // panics
343		})
344
345		defer func() {
346			if recover() == nil {
347				t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
348			}
349		}()
350		b.AddUint8(2) // panics
351	})
352}
353
354// ASN.1
355
356func TestASN1Int64(t *testing.T) {
357	tests := []struct {
358		in   int64
359		want []byte
360	}{
361		{-0x800000, []byte{2, 3, 128, 0, 0}},
362		{-256, []byte{2, 2, 255, 0}},
363		{-129, []byte{2, 2, 255, 127}},
364		{-128, []byte{2, 1, 128}},
365		{-1, []byte{2, 1, 255}},
366		{0, []byte{2, 1, 0}},
367		{1, []byte{2, 1, 1}},
368		{2, []byte{2, 1, 2}},
369		{127, []byte{2, 1, 127}},
370		{128, []byte{2, 2, 0, 128}},
371		{256, []byte{2, 2, 1, 0}},
372		{0x800000, []byte{2, 4, 0, 128, 0, 0}},
373	}
374	for i, tt := range tests {
375		var b Builder
376		b.AddASN1Int64(tt.in)
377		if err := builderBytesEq(&b, tt.want...); err != nil {
378			t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
379		}
380
381		var n int64
382		s := String(b.BytesOrPanic())
383		ok := s.ReadASN1Integer(&n)
384		if !ok || n != tt.in {
385			t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
386				ok, n, tt.in, i)
387		}
388		if len(s) != 0 {
389			t.Errorf("len(s) = %d, want 0", len(s))
390		}
391	}
392}
393
394func TestASN1Uint64(t *testing.T) {
395	tests := []struct {
396		in   uint64
397		want []byte
398	}{
399		{0, []byte{2, 1, 0}},
400		{1, []byte{2, 1, 1}},
401		{2, []byte{2, 1, 2}},
402		{127, []byte{2, 1, 127}},
403		{128, []byte{2, 2, 0, 128}},
404		{256, []byte{2, 2, 1, 0}},
405		{0x800000, []byte{2, 4, 0, 128, 0, 0}},
406		{0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}},
407		{0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}},
408		{0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}},
409	}
410	for i, tt := range tests {
411		var b Builder
412		b.AddASN1Uint64(tt.in)
413		if err := builderBytesEq(&b, tt.want...); err != nil {
414			t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
415		}
416
417		var n uint64
418		s := String(b.BytesOrPanic())
419		ok := s.ReadASN1Integer(&n)
420		if !ok || n != tt.in {
421			t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
422				ok, n, tt.in, i)
423		}
424		if len(s) != 0 {
425			t.Errorf("len(s) = %d, want 0", len(s))
426		}
427	}
428}
429