517 lines
11 KiB
Go
517 lines
11 KiB
Go
// 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) {
|
|
func() {
|
|
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
|
|
})
|
|
}
|
|
|
|
func TestSetError(t *testing.T) {
|
|
const errorStr = "TestSetError"
|
|
var b Builder
|
|
b.SetError(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 TestUnwrite(t *testing.T) {
|
|
var b Builder
|
|
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
|
b.Unwrite(2)
|
|
if err := builderBytesEq(&b, 1, 2, 3); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
func() {
|
|
defer func() {
|
|
if recover() == nil {
|
|
t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
|
|
}
|
|
}()
|
|
b.Unwrite(4) // panics
|
|
}()
|
|
|
|
b = Builder{}
|
|
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
|
b.AddUint8LengthPrefixed(func(b *Builder) {
|
|
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
|
|
|
defer func() {
|
|
if recover() == nil {
|
|
t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
|
|
}
|
|
}()
|
|
b.Unwrite(6) // panics
|
|
})
|
|
|
|
b = Builder{}
|
|
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
|
b.AddUint8LengthPrefixed(func(c *Builder) {
|
|
defer func() {
|
|
if recover() == nil {
|
|
t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
|
|
}
|
|
}()
|
|
b.Unwrite(2) // panics (attempted unwrite while child is pending)
|
|
})
|
|
}
|
|
|
|
func TestFixedBuilderLengthPrefixed(t *testing.T) {
|
|
bufCap := 10
|
|
inner := bytes.Repeat([]byte{0xff}, bufCap-2)
|
|
buf := make([]byte, 0, bufCap)
|
|
b := NewFixedBuilder(buf)
|
|
b.AddUint16LengthPrefixed(func(b *Builder) {
|
|
b.AddBytes(inner)
|
|
})
|
|
if got := b.BytesOrPanic(); len(got) != bufCap {
|
|
t.Errorf("Expected output length to be %d, got %d", bufCap, len(got))
|
|
}
|
|
}
|
|
|
|
func TestFixedBuilderPanicReallocate(t *testing.T) {
|
|
defer func() {
|
|
recover()
|
|
}()
|
|
|
|
b := NewFixedBuilder(make([]byte, 0, 10))
|
|
b1 := NewFixedBuilder(make([]byte, 0, 10))
|
|
b.AddUint16LengthPrefixed(func(b *Builder) {
|
|
*b = *b1
|
|
})
|
|
|
|
t.Error("Builder did not panic")
|
|
}
|
|
|
|
// 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))
|
|
}
|
|
}
|
|
}
|