|  | // Copyright 2017 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package cryptobyte | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "errors" | 
|  | "fmt" | 
|  | "testing" | 
|  | ) | 
|  |  | 
|  | func builderBytesEq(b *Builder, want ...byte) error { | 
|  | got := b.BytesOrPanic() | 
|  | if !bytes.Equal(got, want) { | 
|  | return fmt.Errorf("Bytes() = %v, want %v", got, want) | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func TestContinuationError(t *testing.T) { | 
|  | const errorStr = "TestContinuationError" | 
|  | var b Builder | 
|  | b.AddUint8LengthPrefixed(func(b *Builder) { | 
|  | b.AddUint8(1) | 
|  | panic(BuildError{Err: errors.New(errorStr)}) | 
|  | }) | 
|  |  | 
|  | ret, err := b.Bytes() | 
|  | if ret != nil { | 
|  | t.Error("expected nil result") | 
|  | } | 
|  | if err == nil { | 
|  | t.Fatal("unexpected nil error") | 
|  | } | 
|  | if s := err.Error(); s != errorStr { | 
|  | t.Errorf("expected error %q, got %v", errorStr, s) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestContinuationNonError(t *testing.T) { | 
|  | defer func() { | 
|  | recover() | 
|  | }() | 
|  |  | 
|  | var b Builder | 
|  | b.AddUint8LengthPrefixed(func(b *Builder) { | 
|  | b.AddUint8(1) | 
|  | panic(1) | 
|  | }) | 
|  |  | 
|  | t.Error("Builder did not panic") | 
|  | } | 
|  |  | 
|  | func TestGeneratedPanic(t *testing.T) { | 
|  | defer func() { | 
|  | recover() | 
|  | }() | 
|  |  | 
|  | var b Builder | 
|  | b.AddUint8LengthPrefixed(func(b *Builder) { | 
|  | var p *byte | 
|  | *p = 0 | 
|  | }) | 
|  |  | 
|  | t.Error("Builder did not panic") | 
|  | } | 
|  |  | 
|  | func TestBytes(t *testing.T) { | 
|  | var b Builder | 
|  | v := []byte("foobarbaz") | 
|  | b.AddBytes(v[0:3]) | 
|  | b.AddBytes(v[3:4]) | 
|  | b.AddBytes(v[4:9]) | 
|  | if err := builderBytesEq(&b, v...); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  | s := String(b.BytesOrPanic()) | 
|  | for _, w := range []string{"foo", "bar", "baz"} { | 
|  | var got []byte | 
|  | if !s.ReadBytes(&got, 3) { | 
|  | t.Errorf("ReadBytes() = false, want true (w = %v)", w) | 
|  | } | 
|  | want := []byte(w) | 
|  | if !bytes.Equal(got, want) { | 
|  | t.Errorf("ReadBytes(): got = %v, want %v", got, want) | 
|  | } | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint8(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint8(42) | 
|  | if err := builderBytesEq(&b, 42); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  |  | 
|  | var s String = b.BytesOrPanic() | 
|  | var v uint8 | 
|  | if !s.ReadUint8(&v) { | 
|  | t.Error("ReadUint8() = false, want true") | 
|  | } | 
|  | if v != 42 { | 
|  | t.Errorf("v = %d, want 42", v) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint16(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint16(65534) | 
|  | if err := builderBytesEq(&b, 255, 254); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  | var s String = b.BytesOrPanic() | 
|  | var v uint16 | 
|  | if !s.ReadUint16(&v) { | 
|  | t.Error("ReadUint16() == false, want true") | 
|  | } | 
|  | if v != 65534 { | 
|  | t.Errorf("v = %d, want 65534", v) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint24(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint24(0xfffefd) | 
|  | if err := builderBytesEq(&b, 255, 254, 253); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  |  | 
|  | var s String = b.BytesOrPanic() | 
|  | var v uint32 | 
|  | if !s.ReadUint24(&v) { | 
|  | t.Error("ReadUint8() = false, want true") | 
|  | } | 
|  | if v != 0xfffefd { | 
|  | t.Errorf("v = %d, want fffefd", v) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint24Truncation(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint24(0x10111213) | 
|  | if err := builderBytesEq(&b, 0x11, 0x12, 0x13); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint32(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint32(0xfffefdfc) | 
|  | if err := builderBytesEq(&b, 255, 254, 253, 252); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  |  | 
|  | var s String = b.BytesOrPanic() | 
|  | var v uint32 | 
|  | if !s.ReadUint32(&v) { | 
|  | t.Error("ReadUint8() = false, want true") | 
|  | } | 
|  | if v != 0xfffefdfc { | 
|  | t.Errorf("v = %x, want fffefdfc", v) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUMultiple(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint8(23) | 
|  | b.AddUint32(0xfffefdfc) | 
|  | b.AddUint16(42) | 
|  | if err := builderBytesEq(&b, 23, 255, 254, 253, 252, 0, 42); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  |  | 
|  | var s String = b.BytesOrPanic() | 
|  | var ( | 
|  | x uint8 | 
|  | y uint32 | 
|  | z uint16 | 
|  | ) | 
|  | if !s.ReadUint8(&x) || !s.ReadUint32(&y) || !s.ReadUint16(&z) { | 
|  | t.Error("ReadUint8() = false, want true") | 
|  | } | 
|  | if x != 23 || y != 0xfffefdfc || z != 42 { | 
|  | t.Errorf("x, y, z = %d, %d, %d; want 23, 4294901244, 5", x, y, z) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint8LengthPrefixedSimple(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint8LengthPrefixed(func(c *Builder) { | 
|  | c.AddUint8(23) | 
|  | c.AddUint8(42) | 
|  | }) | 
|  | if err := builderBytesEq(&b, 2, 23, 42); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  |  | 
|  | var base, child String = b.BytesOrPanic(), nil | 
|  | var x, y uint8 | 
|  | if !base.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || | 
|  | !child.ReadUint8(&y) { | 
|  | t.Error("parsing failed") | 
|  | } | 
|  | if x != 23 || y != 42 { | 
|  | t.Errorf("want x, y == 23, 42; got %d, %d", x, y) | 
|  | } | 
|  | if len(base) != 0 { | 
|  | t.Errorf("len(base) = %d, want 0", len(base)) | 
|  | } | 
|  | if len(child) != 0 { | 
|  | t.Errorf("len(child) = %d, want 0", len(child)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint8LengthPrefixedMulti(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint8LengthPrefixed(func(c *Builder) { | 
|  | c.AddUint8(23) | 
|  | c.AddUint8(42) | 
|  | }) | 
|  | b.AddUint8(5) | 
|  | b.AddUint8LengthPrefixed(func(c *Builder) { | 
|  | c.AddUint8(123) | 
|  | c.AddUint8(234) | 
|  | }) | 
|  | if err := builderBytesEq(&b, 2, 23, 42, 5, 2, 123, 234); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  |  | 
|  | var s, child String = b.BytesOrPanic(), nil | 
|  | var u, v, w, x, y uint8 | 
|  | if !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&u) || !child.ReadUint8(&v) || | 
|  | !s.ReadUint8(&w) || !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || !child.ReadUint8(&y) { | 
|  | t.Error("parsing failed") | 
|  | } | 
|  | if u != 23 || v != 42 || w != 5 || x != 123 || y != 234 { | 
|  | t.Errorf("u, v, w, x, y = %d, %d, %d, %d, %d; want 23, 42, 5, 123, 234", | 
|  | u, v, w, x, y) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | if len(child) != 0 { | 
|  | t.Errorf("len(child) = %d, want 0", len(child)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestUint8LengthPrefixedNested(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint8LengthPrefixed(func(c *Builder) { | 
|  | c.AddUint8(5) | 
|  | c.AddUint8LengthPrefixed(func(d *Builder) { | 
|  | d.AddUint8(23) | 
|  | d.AddUint8(42) | 
|  | }) | 
|  | c.AddUint8(123) | 
|  | }) | 
|  | if err := builderBytesEq(&b, 5, 5, 2, 23, 42, 123); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  |  | 
|  | var base, child1, child2 String = b.BytesOrPanic(), nil, nil | 
|  | var u, v, w, x uint8 | 
|  | if !base.ReadUint8LengthPrefixed(&child1) { | 
|  | t.Error("parsing base failed") | 
|  | } | 
|  | if !child1.ReadUint8(&u) || !child1.ReadUint8LengthPrefixed(&child2) || !child1.ReadUint8(&x) { | 
|  | t.Error("parsing child1 failed") | 
|  | } | 
|  | if !child2.ReadUint8(&v) || !child2.ReadUint8(&w) { | 
|  | t.Error("parsing child2 failed") | 
|  | } | 
|  | if u != 5 || v != 23 || w != 42 || x != 123 { | 
|  | t.Errorf("u, v, w, x = %d, %d, %d, %d, want 5, 23, 42, 123", | 
|  | u, v, w, x) | 
|  | } | 
|  | if len(base) != 0 { | 
|  | t.Errorf("len(base) = %d, want 0", len(base)) | 
|  | } | 
|  | if len(child1) != 0 { | 
|  | t.Errorf("len(child1) = %d, want 0", len(child1)) | 
|  | } | 
|  | if len(base) != 0 { | 
|  | t.Errorf("len(child2) = %d, want 0", len(child2)) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestPreallocatedBuffer(t *testing.T) { | 
|  | var buf [5]byte | 
|  | b := NewBuilder(buf[0:0]) | 
|  | b.AddUint8(1) | 
|  | b.AddUint8LengthPrefixed(func(c *Builder) { | 
|  | c.AddUint8(3) | 
|  | c.AddUint8(4) | 
|  | }) | 
|  | b.AddUint16(1286) // Outgrow buf by one byte. | 
|  | want := []byte{1, 2, 3, 4, 0} | 
|  | if !bytes.Equal(buf[:], want) { | 
|  | t.Errorf("buf = %v want %v", buf, want) | 
|  | } | 
|  | if err := builderBytesEq(b, 1, 2, 3, 4, 5, 6); err != nil { | 
|  | t.Error(err) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestWriteWithPendingChild(t *testing.T) { | 
|  | var b Builder | 
|  | b.AddUint8LengthPrefixed(func(c *Builder) { | 
|  | c.AddUint8LengthPrefixed(func(d *Builder) { | 
|  | defer func() { | 
|  | if recover() == nil { | 
|  | t.Errorf("recover() = nil, want error; c.AddUint8() did not panic") | 
|  | } | 
|  | }() | 
|  | c.AddUint8(2) // panics | 
|  |  | 
|  | defer func() { | 
|  | if recover() == nil { | 
|  | t.Errorf("recover() = nil, want error; b.AddUint8() did not panic") | 
|  | } | 
|  | }() | 
|  | b.AddUint8(2) // panics | 
|  | }) | 
|  |  | 
|  | defer func() { | 
|  | if recover() == nil { | 
|  | t.Errorf("recover() = nil, want error; b.AddUint8() did not panic") | 
|  | } | 
|  | }() | 
|  | b.AddUint8(2) // panics | 
|  | }) | 
|  | } | 
|  |  | 
|  | // ASN.1 | 
|  |  | 
|  | func TestASN1Int64(t *testing.T) { | 
|  | tests := []struct { | 
|  | in   int64 | 
|  | want []byte | 
|  | }{ | 
|  | {-0x800000, []byte{2, 3, 128, 0, 0}}, | 
|  | {-256, []byte{2, 2, 255, 0}}, | 
|  | {-129, []byte{2, 2, 255, 127}}, | 
|  | {-128, []byte{2, 1, 128}}, | 
|  | {-1, []byte{2, 1, 255}}, | 
|  | {0, []byte{2, 1, 0}}, | 
|  | {1, []byte{2, 1, 1}}, | 
|  | {2, []byte{2, 1, 2}}, | 
|  | {127, []byte{2, 1, 127}}, | 
|  | {128, []byte{2, 2, 0, 128}}, | 
|  | {256, []byte{2, 2, 1, 0}}, | 
|  | {0x800000, []byte{2, 4, 0, 128, 0, 0}}, | 
|  | } | 
|  | for i, tt := range tests { | 
|  | var b Builder | 
|  | b.AddASN1Int64(tt.in) | 
|  | if err := builderBytesEq(&b, tt.want...); err != nil { | 
|  | t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in) | 
|  | } | 
|  |  | 
|  | var n int64 | 
|  | s := String(b.BytesOrPanic()) | 
|  | ok := s.ReadASN1Integer(&n) | 
|  | if !ok || n != tt.in { | 
|  | t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)", | 
|  | ok, n, tt.in, i) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestASN1Uint64(t *testing.T) { | 
|  | tests := []struct { | 
|  | in   uint64 | 
|  | want []byte | 
|  | }{ | 
|  | {0, []byte{2, 1, 0}}, | 
|  | {1, []byte{2, 1, 1}}, | 
|  | {2, []byte{2, 1, 2}}, | 
|  | {127, []byte{2, 1, 127}}, | 
|  | {128, []byte{2, 2, 0, 128}}, | 
|  | {256, []byte{2, 2, 1, 0}}, | 
|  | {0x800000, []byte{2, 4, 0, 128, 0, 0}}, | 
|  | {0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}}, | 
|  | {0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}}, | 
|  | {0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}}, | 
|  | } | 
|  | for i, tt := range tests { | 
|  | var b Builder | 
|  | b.AddASN1Uint64(tt.in) | 
|  | if err := builderBytesEq(&b, tt.want...); err != nil { | 
|  | t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in) | 
|  | } | 
|  |  | 
|  | var n uint64 | 
|  | s := String(b.BytesOrPanic()) | 
|  | ok := s.ReadASN1Integer(&n) | 
|  | if !ok || n != tt.in { | 
|  | t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)", | 
|  | ok, n, tt.in, i) | 
|  | } | 
|  | if len(s) != 0 { | 
|  | t.Errorf("len(s) = %d, want 0", len(s)) | 
|  | } | 
|  | } | 
|  | } |