2397 lines
56 KiB
Go
2397 lines
56 KiB
Go
package capnp_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/hex"
|
|
"errors"
|
|
"io"
|
|
"math/rand"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
"unsafe"
|
|
|
|
"zombiezen.com/go/capnproto2"
|
|
air "zombiezen.com/go/capnproto2/internal/aircraftlib"
|
|
"zombiezen.com/go/capnproto2/internal/capnptool"
|
|
)
|
|
|
|
// A marshalTest tests whether a message can be encoded then read by the
|
|
// reference capnp implementation.
|
|
type marshalTest struct {
|
|
name string
|
|
|
|
msg *capnp.Message
|
|
typ string
|
|
|
|
text string
|
|
data []byte
|
|
}
|
|
|
|
func makeMarshalTests(t *testing.T) []marshalTest {
|
|
tests := []marshalTest{
|
|
{
|
|
name: "zdateFilledMessage(1)",
|
|
msg: zdateFilledMessage(t, 1),
|
|
typ: "Z",
|
|
text: "(zdatevec = [(year = 2004, month = 12, day = 7)])\n",
|
|
},
|
|
{
|
|
name: "zdateFilledMessage(10)",
|
|
msg: zdateFilledMessage(t, 10),
|
|
typ: "Z",
|
|
text: "(zdatevec = [(year = 2004, month = 12, day = 7), (year = 2005, month = 12, day = 7), (year = 2006, month = 12, day = 7), (year = 2007, month = 12, day = 7), (year = 2008, month = 12, day = 7), (year = 2009, month = 12, day = 7), (year = 2010, month = 12, day = 7), (year = 2011, month = 12, day = 7), (year = 2012, month = 12, day = 7), (year = 2013, month = 12, day = 7)])\n",
|
|
},
|
|
{
|
|
name: "zdataFilledMessage(20)",
|
|
msg: zdataFilledMessage(t, 20),
|
|
typ: "Z",
|
|
text: `(zdata = (data = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13"))` + "\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 9, 0, 0, 0,
|
|
0, 0, 0, 0, 3, 0, 1, 0,
|
|
28, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 162, 0, 0, 0,
|
|
0, 1, 2, 3, 4, 5, 6, 7,
|
|
8, 9, 10, 11, 12, 13, 14, 15,
|
|
16, 17, 18, 19, 0, 0, 0, 0,
|
|
},
|
|
},
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := air.NewRootZjob(seg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tests = append(tests, marshalTest{
|
|
name: "empty Zjob",
|
|
msg: msg,
|
|
typ: "Zjob",
|
|
text: "()\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 3, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 2, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
zjob, err := air.NewRootZjob(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := zjob.SetCmd("abc"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tests = append(tests, marshalTest{
|
|
name: "Zjob with text",
|
|
msg: msg,
|
|
typ: "Zjob",
|
|
text: "(cmd = \"abc\")\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 4, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 2, 0,
|
|
5, 0, 0, 0, 34, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
97, 98, 99, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
zjob, err := air.NewRootZjob(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
args, err := zjob.NewArgs(1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := args.Set(0, "xyz"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tests = append(tests, marshalTest{
|
|
name: "Zjob with text list",
|
|
msg: msg,
|
|
typ: "Zjob",
|
|
text: "(args = [\"xyz\"])\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 5, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 2, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 14, 0, 0, 0,
|
|
1, 0, 0, 0, 34, 0, 0, 0,
|
|
120, 121, 122, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
zjob, err := air.NewRootZjob(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := zjob.SetCmd("abc"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
args, err := zjob.NewArgs(1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := args.Set(0, "xyz"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tests = append(tests, marshalTest{
|
|
name: "Zjob with text and text list",
|
|
msg: msg,
|
|
typ: "Zjob",
|
|
text: "(cmd = \"abc\", args = [\"xyz\"])\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 6, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 2, 0,
|
|
5, 0, 0, 0, 34, 0, 0, 0,
|
|
5, 0, 0, 0, 14, 0, 0, 0,
|
|
97, 98, 99, 0, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 34, 0, 0, 0,
|
|
120, 121, 122, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
server, err := air.NewRootZserver(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := server.NewWaitingjobs(1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "Zserver with one empty job",
|
|
msg: msg,
|
|
typ: "Zserver",
|
|
text: "(waitingjobs = [()])\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 5, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 23, 0, 0, 0,
|
|
4, 0, 0, 0, 0, 0, 2, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
server, err := air.NewRootZserver(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
joblist, err := server.NewWaitingjobs(1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := joblist.At(0).SetCmd("abc"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
args, err := joblist.At(0).NewArgs(1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := args.Set(0, "xyz"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "Zserver with one full job",
|
|
msg: msg,
|
|
typ: "Zserver",
|
|
text: "(waitingjobs = [(cmd = \"abc\", args = [\"xyz\"])])\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 8, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 23, 0, 0, 0,
|
|
4, 0, 0, 0, 0, 0, 2, 0,
|
|
5, 0, 0, 0, 34, 0, 0, 0,
|
|
5, 0, 0, 0, 14, 0, 0, 0,
|
|
97, 98, 99, 0, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 34, 0, 0, 0,
|
|
120, 121, 122, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
server, err := air.NewRootZserver(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
joblist, err := server.NewWaitingjobs(2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := joblist.At(0).SetCmd("abc"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := joblist.At(1).SetCmd("xyz"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "Zserver with two jobs",
|
|
msg: msg,
|
|
typ: "Zserver",
|
|
text: "(waitingjobs = [(cmd = \"abc\"), (cmd = \"xyz\")])\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 9, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 39, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 2, 0,
|
|
13, 0, 0, 0, 34, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
9, 0, 0, 0, 34, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
'a', 'b', 'c', 0, 0, 0, 0, 0,
|
|
'x', 'y', 'z', 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, scratch, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in seg
|
|
segbag, err := air.NewRootBag(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in scratch
|
|
xc, err := air.NewRootCounter(scratch)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
xc.SetSize(9)
|
|
|
|
// copy from scratch to seg
|
|
if err = segbag.SetCounter(xc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "copy struct between messages",
|
|
msg: msg,
|
|
typ: "Bag",
|
|
text: "(counter = (size = 9))\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 6, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 1, 0, 3, 0,
|
|
9, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, scratch, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in seg
|
|
segbag, err := air.NewRootBag(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in scratch
|
|
xc, err := air.NewRootCounter(scratch)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
xc.SetSize(9)
|
|
if err := xc.SetWords("hello"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// copy from scratch to seg
|
|
if err = segbag.SetCounter(xc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "copy struct with text between messages",
|
|
msg: msg,
|
|
typ: "Bag",
|
|
text: "(counter = (size = 9, words = \"hello\"))\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 7, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 1, 0, 3, 0,
|
|
9, 0, 0, 0, 0, 0, 0, 0,
|
|
9, 0, 0, 0, 50, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
'h', 'e', 'l', 'l', 'o', 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, scratch, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in seg
|
|
segbag, err := air.NewRootBag(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in scratch
|
|
xc, err := air.NewRootCounter(scratch)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
xc.SetSize(9)
|
|
wl, err := xc.NewWordlist(2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := wl.Set(0, "hello"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := wl.Set(1, "bye"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// copy from scratch to seg
|
|
if err = segbag.SetCounter(xc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "copy struct with list of text between messages",
|
|
msg: msg,
|
|
typ: "Bag",
|
|
text: "(counter = (size = 9, wordlist = [\"hello\", \"bye\"]))\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 10, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 1, 0, 3, 0,
|
|
9, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
5, 0, 0, 0, 22, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
5, 0, 0, 0, 34, 0, 0, 0,
|
|
'h', 'e', 'l', 'l', 'o', 0, 0, 0,
|
|
'b', 'y', 'e', 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, scratch, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in seg
|
|
segbag, err := air.NewRootBag(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in scratch
|
|
xc, err := air.NewRootCounter(scratch)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
xc.SetSize(9)
|
|
if err := xc.SetWords("abc"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wl, err := xc.NewWordlist(2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := wl.Set(0, "hello"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := wl.Set(1, "byenow"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// copy from scratch to seg
|
|
if err = segbag.SetCounter(xc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "copy struct with data, text, and list of text between messages",
|
|
msg: msg,
|
|
typ: "Bag",
|
|
text: "(counter = (size = 9, words = \"abc\", wordlist = [\"hello\", \"byenow\"]))\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 11, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 1, 0, 3, 0,
|
|
9, 0, 0, 0, 0, 0, 0, 0,
|
|
9, 0, 0, 0, 34, 0, 0, 0,
|
|
9, 0, 0, 0, 22, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
97, 98, 99, 0, 0, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
5, 0, 0, 0, 58, 0, 0, 0,
|
|
'h', 'e', 'l', 'l', 'o', 0, 0, 0,
|
|
'b', 'y', 'e', 'n', 'o', 'w', 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, scratch, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in seg
|
|
segbag, err := air.NewRootBag(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// in scratch
|
|
xc, err := air.NewRootCounter(scratch)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bl, err := xc.NewBitlist(3)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
bl.Set(0, true)
|
|
bl.Set(1, false)
|
|
bl.Set(2, true)
|
|
|
|
// copy from scratch to seg
|
|
if err = segbag.SetCounter(xc); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "copy struct with bit list between messages",
|
|
msg: msg,
|
|
typ: "Bag",
|
|
text: "(counter = (size = 0, bitlist = [true, false, true]))\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 7, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 1, 0, 3, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
1, 0, 0, 0, 25, 0, 0, 0,
|
|
5, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
holder, err := air.NewRootHoldsVerEmptyList(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
elist, err := air.NewVerEmpty_List(seg, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := holder.SetMylist(elist); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "V0 list of empty",
|
|
msg: msg,
|
|
typ: "HoldsVerEmptyList",
|
|
text: "(mylist = [(), ()])\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 3, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 7, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
holder, err := air.NewRootNester1Capn(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
initNester(t, holder, "furiosa", "max")
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "list inside a struct",
|
|
msg: msg,
|
|
typ: "Nester1Capn",
|
|
text: "(strs = [\"furiosa\", \"max\"])\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 6, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 66, 0, 0, 0,
|
|
5, 0, 0, 0, 34, 0, 0, 0,
|
|
102, 117, 114, 105, 111, 115, 97, 0,
|
|
109, 97, 120, 0, 0, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
{
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
holder, err := air.NewRootRWTestCapn(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mat, err := capnp.NewPointerList(seg, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := holder.SetNestMatrix(mat); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
row0, err := air.NewNester1Capn_List(seg, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := mat.Set(0, row0); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
initNester(t, row0.At(0), "z", "w")
|
|
initNester(t, row0.At(1), "q", "r")
|
|
|
|
row1, err := air.NewNester1Capn_List(seg, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := mat.Set(1, row1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
initNester(t, row1.At(0), "zebra", "wally")
|
|
initNester(t, row1.At(1), "qubert", "rocks")
|
|
|
|
tests = append(tests, marshalTest{
|
|
name: "doubly-nested list of struct that has a list field",
|
|
msg: msg,
|
|
typ: "RWTestCapn",
|
|
text: `(nestMatrix = [[(strs = ["z", "w"]), (strs = ["q", "r"])], [(strs = ["zebra", "wally"]), (strs = ["qubert", "rocks"])]])` + "\n",
|
|
data: []byte{
|
|
0, 0, 0, 0, 26, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 23, 0, 0, 0,
|
|
45, 0, 0, 0, 23, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 1, 0,
|
|
5, 0, 0, 0, 22, 0, 0, 0,
|
|
17, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
122, 0, 0, 0, 0, 0, 0, 0,
|
|
119, 0, 0, 0, 0, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
113, 0, 0, 0, 0, 0, 0, 0,
|
|
114, 0, 0, 0, 0, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 1, 0,
|
|
5, 0, 0, 0, 22, 0, 0, 0,
|
|
17, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
122, 101, 98, 114, 97, 0, 0, 0,
|
|
119, 97, 108, 108, 121, 0, 0, 0,
|
|
5, 0, 0, 0, 58, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
113, 117, 98, 101, 114, 116, 0, 0,
|
|
114, 111, 99, 107, 115, 0, 0, 0,
|
|
},
|
|
})
|
|
}
|
|
|
|
return tests
|
|
}
|
|
|
|
func TestMarshalShouldMatchData(t *testing.T) {
|
|
t.Parallel()
|
|
for _, test := range makeMarshalTests(t) {
|
|
if test.data == nil {
|
|
// TODO(light): backfill all data
|
|
continue
|
|
}
|
|
data, err := test.msg.Marshal()
|
|
if err != nil {
|
|
t.Errorf("%s: marshal error: %v", test.name, err)
|
|
continue
|
|
}
|
|
want, err := encodeTestMessage(test.typ, test.text, test.data)
|
|
if err != nil {
|
|
t.Errorf("%s: %v", test.name, err)
|
|
continue
|
|
}
|
|
if !bytes.Equal(data, want) {
|
|
t.Errorf("%s: Marshal returned:\n%s\nwant:\n%s", test.name, hex.Dump(data), hex.Dump(want))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarshalShouldMatchTextWhenDecoded(t *testing.T) {
|
|
t.Parallel()
|
|
tool, err := capnptool.Find()
|
|
if err != nil {
|
|
t.Skip("capnp tool not found:", err)
|
|
}
|
|
for _, test := range makeMarshalTests(t) {
|
|
data, err := test.msg.Marshal()
|
|
if err != nil {
|
|
t.Errorf("%s: marshal error: %v", test.name, err)
|
|
continue
|
|
}
|
|
text, err := tool.Decode(capnptool.Type{SchemaPath: schemaPath, Name: test.typ}, bytes.NewReader(data))
|
|
if err != nil {
|
|
t.Errorf("%s: capnp decode: %v", test.name, err)
|
|
continue
|
|
}
|
|
if text != test.text {
|
|
t.Errorf("%s: decoded to:\n%q; want:\n%q", test.name, text, test.text)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarshalPackedShouldMatchTextWhenDecoded(t *testing.T) {
|
|
t.Parallel()
|
|
tool, err := capnptool.Find()
|
|
if err != nil {
|
|
t.Skip("capnp tool not found:", err)
|
|
}
|
|
for _, test := range makeMarshalTests(t) {
|
|
data, err := test.msg.MarshalPacked()
|
|
if err != nil {
|
|
t.Errorf("%s: marshal error: %v", test.name, err)
|
|
continue
|
|
}
|
|
text, err := tool.DecodePacked(capnptool.Type{SchemaPath: schemaPath, Name: test.typ}, bytes.NewReader(data))
|
|
if err != nil {
|
|
t.Errorf("%s: capnp decode: %v", test.name, err)
|
|
continue
|
|
}
|
|
if text != test.text {
|
|
t.Errorf("%s: decoded to:\n%q; want:\n%q", test.name, text, test.text)
|
|
}
|
|
}
|
|
}
|
|
|
|
type bitListTest struct {
|
|
list []bool
|
|
text string
|
|
}
|
|
|
|
var bitListTests = []bitListTest{
|
|
{
|
|
[]bool{true, false, true},
|
|
"(boolvec = [true, false, true])\n",
|
|
},
|
|
{
|
|
[]bool{false},
|
|
"(boolvec = [false])\n",
|
|
},
|
|
{
|
|
[]bool{true},
|
|
"(boolvec = [true])\n",
|
|
},
|
|
{
|
|
[]bool{false, true},
|
|
"(boolvec = [false, true])\n",
|
|
},
|
|
{
|
|
[]bool{true, true},
|
|
"(boolvec = [true, true])\n",
|
|
},
|
|
{
|
|
[]bool{false, false, true},
|
|
"(boolvec = [false, false, true])\n",
|
|
},
|
|
{
|
|
[]bool{true, false, true, false, true},
|
|
"(boolvec = [true, false, true, false, true])\n",
|
|
},
|
|
{
|
|
[]bool{
|
|
false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false,
|
|
false, false, false, false, false, false, false, false,
|
|
true, true,
|
|
},
|
|
"(boolvec = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true])\n",
|
|
},
|
|
}
|
|
|
|
func (blt bitListTest) makeMessage() (*capnp.Message, error) {
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
z, err := air.NewRootZ(seg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
list, err := capnp.NewBitList(seg, int32(len(blt.list)))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for i := range blt.list {
|
|
list.Set(i, blt.list[i])
|
|
}
|
|
if err := z.SetBoolvec(list); err != nil {
|
|
return nil, err
|
|
}
|
|
return msg, nil
|
|
}
|
|
|
|
func TestBitList(t *testing.T) {
|
|
t.Parallel()
|
|
for _, test := range bitListTests {
|
|
msg, err := test.makeMessage()
|
|
if err != nil {
|
|
t.Errorf("%v: make message: %v", test.list, err)
|
|
continue
|
|
}
|
|
|
|
z, err := air.ReadRootZ(msg)
|
|
if err != nil {
|
|
t.Errorf("%v: read root Z: %v", test.list, err)
|
|
continue
|
|
}
|
|
if w := z.Which(); w != air.Z_Which_boolvec {
|
|
t.Errorf("%v: root.Which() = %v; want boolvec", test.list, w)
|
|
continue
|
|
}
|
|
list, err := z.Boolvec()
|
|
if err != nil {
|
|
t.Errorf("%v: read Z.boolvec: %v", test.list, err)
|
|
continue
|
|
}
|
|
if n := list.Len(); n != len(test.list) {
|
|
t.Errorf("%v: len(Z.boolvec) = %d; want %d", test.list, n, len(test.list))
|
|
continue
|
|
}
|
|
for i := range test.list {
|
|
if li := list.At(i); li != test.list[i] {
|
|
t.Errorf("%v: Z.boolvec[%d] = %t; want %t", test.list, i, li, test.list[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBitList_Decode(t *testing.T) {
|
|
t.Parallel()
|
|
tool, err := capnptool.Find()
|
|
if err != nil {
|
|
t.Skip("capnp tool not found:", err)
|
|
}
|
|
for _, test := range bitListTests {
|
|
msg, err := test.makeMessage()
|
|
if err != nil {
|
|
t.Errorf("%v: make message: %v", test.list, err)
|
|
continue
|
|
}
|
|
out, err := msg.Marshal()
|
|
if err != nil {
|
|
t.Errorf("%v: marshal: %v", test.list, err)
|
|
continue
|
|
}
|
|
text, err := tool.Decode(capnptool.Type{SchemaPath: schemaPath, Name: "Z"}, bytes.NewReader(out))
|
|
if err != nil {
|
|
t.Errorf("%v: capnp decode: %v", test.list, err)
|
|
continue
|
|
}
|
|
if text != test.text {
|
|
t.Errorf("%v: capnp decode = %q; want %q", test.list, text, test.text)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestZDataAccessors(t *testing.T) {
|
|
t.Parallel()
|
|
data := mustEncodeTestMessage(t, "Z", `(zdata = (data = "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13"))`, []byte{
|
|
0, 0, 0, 0, 9, 0, 0, 0,
|
|
0, 0, 0, 0, 3, 0, 1, 0,
|
|
28, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 162, 0, 0, 0,
|
|
0, 1, 2, 3, 4, 5, 6, 7,
|
|
8, 9, 10, 11, 12, 13, 14, 15,
|
|
16, 17, 18, 19, 0, 0, 0, 0,
|
|
})
|
|
|
|
msg, err := capnp.Unmarshal(data)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
z, err := air.ReadRootZ(msg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootZ:", err)
|
|
}
|
|
|
|
if z.Which() != air.Z_Which_zdata {
|
|
t.Fatalf("z.Which() = %v; want zdata", z.Which())
|
|
}
|
|
zdata, err := z.Zdata()
|
|
if err != nil {
|
|
t.Fatal("z.Zdata():", err)
|
|
}
|
|
d, err := zdata.Data()
|
|
if err != nil {
|
|
t.Fatal("z.Zdata().Data():", err)
|
|
}
|
|
if len(d) != 20 {
|
|
t.Errorf("z.Zdata().Data() len = %d; want 20", len(d))
|
|
}
|
|
for i := range d {
|
|
if d[i] != byte(i) {
|
|
t.Errorf("z.Zdata().Data()[%d] = %d; want %d", i, d[i], i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInterfaceSet(t *testing.T) {
|
|
t.Parallel()
|
|
cl := air.Echo{Client: capnp.ErrorClient(errors.New("foo"))}
|
|
_, s, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
base, err := air.NewRootEchoBase(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
base.SetEcho(cl)
|
|
|
|
if base.Echo() != cl {
|
|
t.Errorf("base.Echo() = %#v; want %#v", base.Echo(), cl)
|
|
}
|
|
}
|
|
|
|
func TestInterfaceSetNull(t *testing.T) {
|
|
t.Parallel()
|
|
cl := air.Echo{Client: capnp.ErrorClient(errors.New("foo"))}
|
|
msg, s, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
base, err := air.NewRootEchoBase(s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
base.SetEcho(cl)
|
|
|
|
base.SetEcho(air.Echo{})
|
|
|
|
if e := base.Echo().Client; e != nil {
|
|
t.Errorf("base.Echo() = %#v; want nil", e)
|
|
}
|
|
if len(msg.CapTable) != 1 {
|
|
t.Errorf("msg.CapTable = %#v; want len = 1", msg.CapTable)
|
|
}
|
|
}
|
|
|
|
func TestInterfaceCopyToOtherMessage(t *testing.T) {
|
|
t.Parallel()
|
|
cl := air.Echo{Client: capnp.ErrorClient(errors.New("foo"))}
|
|
_, s1, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
base1, err := air.NewRootEchoBase(s1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := base1.SetEcho(cl); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, s2, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
hoth2, err := air.NewRootHoth(s2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := hoth2.SetBase(base1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if base, err := hoth2.Base(); err != nil {
|
|
t.Errorf("hoth2.Base() error: %v", err)
|
|
} else if base.Echo() != cl {
|
|
t.Errorf("hoth2.Base().Echo() = %#v; want %#v", base.Echo(), cl)
|
|
}
|
|
tab2 := s2.Message().CapTable
|
|
if len(tab2) == 1 {
|
|
if tab2[0] != cl.Client {
|
|
t.Errorf("s2.Message().CapTable[0] = %#v; want %#v", tab2[0], cl.Client)
|
|
}
|
|
} else {
|
|
t.Errorf("len(s2.Message().CapTable) = %d; want 1", len(tab2))
|
|
}
|
|
}
|
|
|
|
func TestInterfaceCopyToOtherMessageWithCaps(t *testing.T) {
|
|
t.Parallel()
|
|
cl := air.Echo{Client: capnp.ErrorClient(errors.New("foo"))}
|
|
_, s1, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
base1, err := air.NewRootEchoBase(s1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := base1.SetEcho(cl); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, s2, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s2.Message().AddCap(nil)
|
|
hoth2, err := air.NewRootHoth(s2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := hoth2.SetBase(base1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if base, err := hoth2.Base(); err != nil {
|
|
t.Errorf("hoth2.Base() error: %v", err)
|
|
} else if base.Echo() != cl {
|
|
t.Errorf("hoth2.Base().Echo() = %#v; want %#v", base.Echo(), cl)
|
|
}
|
|
tab2 := s2.Message().CapTable
|
|
if len(tab2) != 2 {
|
|
t.Errorf("len(s2.Message().CapTable) = %d; want 2", len(tab2))
|
|
}
|
|
}
|
|
|
|
func TestReadListInStruct(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(t, "Nester1Capn", "(strs = [\"furiosa\", \"max\"])", []byte{
|
|
0, 0, 0, 0, 6, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 66, 0, 0, 0,
|
|
5, 0, 0, 0, 34, 0, 0, 0,
|
|
102, 117, 114, 105, 111, 115, 97, 0,
|
|
109, 97, 120, 0, 0, 0, 0, 0,
|
|
})
|
|
msg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
holder, err := air.ReadRootNester1Capn(msg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootNester1Capn:", err)
|
|
}
|
|
strs, err := holder.Strs()
|
|
if err != nil {
|
|
t.Fatal("Nester1Capn.strs:", err)
|
|
}
|
|
if strs.Len() == 2 {
|
|
check := func(i int, want string) {
|
|
s, err := strs.At(i)
|
|
if err != nil {
|
|
t.Errorf("Nester1Capn.strs[%d] error: %v", i, err)
|
|
}
|
|
if s != want {
|
|
t.Errorf("Nester1Capn.strs[%d] = %q; want %q", i, s, want)
|
|
}
|
|
}
|
|
check(0, "furiosa")
|
|
check(1, "max")
|
|
} else {
|
|
t.Errorf("len(Nester1Capn.strs) = %d; want 2", strs.Len())
|
|
}
|
|
}
|
|
|
|
func TestReadNestedListOfStructWithList(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(
|
|
t,
|
|
"RWTestCapn",
|
|
`(nestMatrix = [[(strs = ["z", "w"]), (strs = ["q", "r"])], [(strs = ["zebra", "wally"]), (strs = ["qubert", "rocks"])]])`,
|
|
[]byte{
|
|
0, 0, 0, 0, 26, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 23, 0, 0, 0,
|
|
45, 0, 0, 0, 23, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 1, 0,
|
|
5, 0, 0, 0, 22, 0, 0, 0,
|
|
17, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
122, 0, 0, 0, 0, 0, 0, 0,
|
|
119, 0, 0, 0, 0, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
5, 0, 0, 0, 18, 0, 0, 0,
|
|
113, 0, 0, 0, 0, 0, 0, 0,
|
|
114, 0, 0, 0, 0, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 1, 0,
|
|
5, 0, 0, 0, 22, 0, 0, 0,
|
|
17, 0, 0, 0, 22, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
122, 101, 98, 114, 97, 0, 0, 0,
|
|
119, 97, 108, 108, 121, 0, 0, 0,
|
|
5, 0, 0, 0, 58, 0, 0, 0,
|
|
5, 0, 0, 0, 50, 0, 0, 0,
|
|
113, 117, 98, 101, 114, 116, 0, 0,
|
|
114, 111, 99, 107, 115, 0, 0, 0,
|
|
})
|
|
msg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
holder, err := air.ReadRootRWTestCapn(msg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootRWTestCapn:", err)
|
|
}
|
|
mat, err := holder.NestMatrix()
|
|
if err != nil {
|
|
t.Fatal("RWTestCapn:", err)
|
|
}
|
|
check := func(i, j int, want ...string) {
|
|
if i >= mat.Len() {
|
|
t.Errorf("len(RWTestCapn.nestMatrix) = %d; tried to index %d", mat.Len(), i)
|
|
return
|
|
}
|
|
row, err := mat.At(i)
|
|
if err != nil {
|
|
t.Errorf("RWTestCapn.nestMatrix[%d]: %v", i, err)
|
|
return
|
|
}
|
|
rowList := air.Nester1Capn_List{List: capnp.ToList(row)}
|
|
if j >= rowList.Len() {
|
|
t.Errorf("len(RWTestCapn.nestMatrix[%d]) = %d; tried to index %d", i, rowList.Len(), j)
|
|
return
|
|
}
|
|
strs, err := rowList.At(j).Strs()
|
|
if err != nil {
|
|
t.Errorf("RWTestCapn.nestMatrix[%d][%d].strs: %v", i, j, err)
|
|
return
|
|
}
|
|
if strs.Len() != len(want) {
|
|
t.Errorf("len(RWTestCapn.nestMatrix[%d][%d].strs) = %d; want %d", i, j, strs.Len(), len(want))
|
|
return
|
|
}
|
|
for k := 0; k < strs.Len(); k++ {
|
|
s, err := strs.At(k)
|
|
if err != nil {
|
|
t.Errorf("RWTestCapn.nestMatrix[%d][%d].strs[%d]: %v", i, j, k, err)
|
|
continue
|
|
}
|
|
if s != want[k] {
|
|
t.Errorf("RWTestCapn.nestMatrix[%d][%d].strs[%d] = %q; want %q", i, j, k, s, want[k])
|
|
}
|
|
}
|
|
}
|
|
check(0, 0, "z", "w")
|
|
check(0, 1, "q", "r")
|
|
check(1, 0, "zebra", "wally")
|
|
check(1, 1, "qubert", "rocks")
|
|
}
|
|
|
|
func TestDataVersioningAvoidsUnnecessaryTruncation(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(t, "VerTwoDataTwoPtr", "(val = 9, duo = 8, ptr1 = (val = 77), ptr2 = (val = 55))", []byte{
|
|
0, 0, 0, 0, 7, 0, 0, 0,
|
|
0, 0, 0, 0, 2, 0, 2, 0,
|
|
9, 0, 0, 0, 0, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 0, 0,
|
|
4, 0, 0, 0, 1, 0, 0, 0,
|
|
4, 0, 0, 0, 1, 0, 0, 0,
|
|
77, 0, 0, 0, 0, 0, 0, 0,
|
|
55, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
want := mustEncodeTestMessage(t, "Wrap2x2", "(mightNotBeReallyEmpty = (val = 9, duo = 8, ptr1 = (val = 77), ptr2 = (val = 55)))", []byte{
|
|
0, 0, 0, 0, 8, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
0, 0, 0, 0, 2, 0, 2, 0,
|
|
9, 0, 0, 0, 0, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 0, 0,
|
|
4, 0, 0, 0, 1, 0, 0, 0,
|
|
4, 0, 0, 0, 1, 0, 0, 0,
|
|
77, 0, 0, 0, 0, 0, 0, 0,
|
|
55, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
msg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
|
|
// Read in the message as if it's an old client (less fields in schema).
|
|
oldRoot, err := air.ReadRootVerEmpty(msg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootVerEmpty:", err)
|
|
}
|
|
|
|
// Store the larger message into another segment.
|
|
freshMsg, freshSeg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal("NewMessage:", err)
|
|
}
|
|
wrapEmpty, err := air.NewRootWrapEmpty(freshSeg)
|
|
if err != nil {
|
|
t.Fatal("NewRootWrapEmpty:", err)
|
|
}
|
|
if err := wrapEmpty.SetMightNotBeReallyEmpty(oldRoot); err != nil {
|
|
t.Fatal("SetMightNotBeReallyEmpty:", err)
|
|
}
|
|
|
|
// Verify that it matches the expected serialization.
|
|
out, err := freshMsg.Marshal()
|
|
if err != nil {
|
|
t.Fatal("Marshal:", err)
|
|
}
|
|
if !bytes.Equal(out, want) {
|
|
t.Errorf("After copy, data is:\n%s\nwant:\n%s", hex.Dump(out), hex.Dump(want))
|
|
}
|
|
}
|
|
|
|
func TestZserverAccessors(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(t, "Zserver", `(waitingjobs = [(cmd = "abc"), (cmd = "xyz")])`, []byte{
|
|
0, 0, 0, 0, 9, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 39, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 2, 0,
|
|
13, 0, 0, 0, 34, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
9, 0, 0, 0, 34, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
97, 98, 99, 0, 0, 0, 0, 0,
|
|
120, 121, 122, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
msg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
|
|
zserver, err := air.ReadRootZserver(msg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootZserver:", err)
|
|
}
|
|
joblist, err := zserver.Waitingjobs()
|
|
if err != nil {
|
|
t.Fatal("Zserver.waitingjobs:", err)
|
|
}
|
|
if joblist.Len() != 2 {
|
|
t.Fatalf("len(Zserver.waitingjobs) = %d; want 2", joblist.Len())
|
|
}
|
|
checkCmd := func(i int, want string) {
|
|
cmd, err := joblist.At(i).Cmd()
|
|
if err != nil {
|
|
t.Errorf("Zserver.waitingjobs[%d].cmd error: %v", i, err)
|
|
return
|
|
}
|
|
if cmd != want {
|
|
t.Errorf("Zserver.waitingjobs[%d].cmd = %q; want %q", i, cmd, want)
|
|
}
|
|
}
|
|
checkCmd(0, "abc")
|
|
checkCmd(1, "xyz")
|
|
}
|
|
|
|
func TestEnumFromString(t *testing.T) {
|
|
t.Parallel()
|
|
tests := []struct {
|
|
s string
|
|
ap air.Airport
|
|
}{
|
|
{"jfk", air.Airport_jfk},
|
|
{"notEverMatching", 0},
|
|
}
|
|
for _, test := range tests {
|
|
if ap := air.AirportFromString(test.s); ap != test.ap {
|
|
t.Errorf("air.AirportFromString(%q) = %v; want %v", test.s, ap, test.ap)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDefaultStructField(t *testing.T) {
|
|
t.Parallel()
|
|
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root, err := air.NewRootStackingRoot(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a, err := root.AWithDefault()
|
|
|
|
if err != nil {
|
|
t.Error("StackingRoot.aWithDefault error:", err)
|
|
}
|
|
if a.Num() != 42 {
|
|
t.Errorf("StackingRoot.aWithDefault = %d; want 42", a.Num())
|
|
}
|
|
}
|
|
|
|
func TestDataTextCopyOptimization(t *testing.T) {
|
|
t.Parallel()
|
|
_, seg1, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root, err := air.NewRootNester1Capn(seg1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, seg2, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
strsl, err := capnp.NewTextList(seg2, 256)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for i := 0; i < strsl.Len(); i++ {
|
|
strsl.Set(i, "testess")
|
|
}
|
|
|
|
err = root.SetStrs(strsl)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
strsl, err = root.Strs()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strsl.Len() != 256 {
|
|
t.Errorf("strsl.Len() = %d; want 256", strsl.Len())
|
|
}
|
|
for i := 0; i < strsl.Len(); i++ {
|
|
s, err := strsl.At(i)
|
|
if err != nil {
|
|
t.Errorf("strsl.At(%d) error: %v", i, err)
|
|
continue
|
|
}
|
|
if s != "testess" {
|
|
t.Errorf("strsl.At(%d) = %q; want \"testess\"", i, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// highlight how much faster text movement between segments
|
|
// is when special casing Text and Data
|
|
//
|
|
// run this test with capnp.go:1334-1341 commented in/out to compare.
|
|
//
|
|
func BenchmarkTextMovementBetweenSegments(b *testing.B) {
|
|
buf := make([]byte, 1<<21)
|
|
buf2 := make([]byte, 1<<21)
|
|
|
|
text := make([]byte, 1<<20)
|
|
for i := range text {
|
|
text[i] = byte(65 + rand.Int()%26)
|
|
}
|
|
|
|
astr := make([]string, 1000)
|
|
for i := range astr {
|
|
astr[i] = string(text[i*1000 : (i+1)*1000])
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, seg, _ := capnp.NewMessage(capnp.SingleSegment(buf[:0]))
|
|
_, scratch, _ := capnp.NewMessage(capnp.SingleSegment(buf2[:0]))
|
|
|
|
ht, _ := air.NewRootHoldsText(seg)
|
|
// Purposefully created in another segment.
|
|
tl, _ := capnp.NewTextList(scratch, 1000)
|
|
for j := 0; j < 1000; j++ {
|
|
tl.Set(j, astr[j])
|
|
}
|
|
|
|
ht.SetLst(tl)
|
|
}
|
|
}
|
|
|
|
func TestV1DataVersioningBiggerToEmpty(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(t, "HoldsVerTwoDataList", "(mylist = [(val = 27, duo = 26), (val = 42, duo = 41)])", []byte{
|
|
0, 0, 0, 0, 7, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 39, 0, 0, 0,
|
|
8, 0, 0, 0, 2, 0, 0, 0,
|
|
27, 0, 0, 0, 0, 0, 0, 0,
|
|
26, 0, 0, 0, 0, 0, 0, 0,
|
|
42, 0, 0, 0, 0, 0, 0, 0,
|
|
41, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
remsg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
|
|
// 0 data
|
|
func() {
|
|
reHolder0, err := air.ReadRootHoldsVerEmptyList(remsg)
|
|
if err != nil {
|
|
t.Error("ReadRootHoldsVerEmptyList:", err)
|
|
return
|
|
}
|
|
list0, err := reHolder0.Mylist()
|
|
if err != nil {
|
|
t.Error("HoldsVerEmptyList.mylist:", err)
|
|
return
|
|
}
|
|
if list0.Len() != 2 {
|
|
t.Errorf("len(HoldsVerEmptyList.mylist) = %d; want 2", list0.Len())
|
|
}
|
|
}()
|
|
|
|
// 1 datum
|
|
func() {
|
|
reHolder1, err := air.ReadRootHoldsVerOneDataList(remsg)
|
|
if err != nil {
|
|
t.Error("ReadRootHoldsVerOneDataList:", err)
|
|
return
|
|
}
|
|
list1, err := reHolder1.Mylist()
|
|
if err != nil {
|
|
t.Error("HoldsVerOneDataList.mylist:", err)
|
|
return
|
|
}
|
|
if list1.Len() == 2 {
|
|
if v := list1.At(0).Val(); v != 27 {
|
|
t.Errorf("HoldsVerOneDataList.mylist[0].val = %d; want 27", v)
|
|
}
|
|
if v := list1.At(1).Val(); v != 42 {
|
|
t.Errorf("HoldsVerOneDataList.mylist[1].val = %d; want 42", v)
|
|
}
|
|
} else {
|
|
t.Errorf("len(HoldsVerOneDataList.mylist) = %d; want 2", list1.Len())
|
|
}
|
|
}()
|
|
|
|
// 2 data
|
|
func() {
|
|
reHolder2, err := air.ReadRootHoldsVerTwoDataList(remsg)
|
|
if err != nil {
|
|
t.Error("ReadRootHoldsVerTwoDataList:", err)
|
|
return
|
|
}
|
|
list2, err := reHolder2.Mylist()
|
|
if err != nil {
|
|
t.Error("HoldsVerTwoDataList.mylist:", err)
|
|
return
|
|
}
|
|
if list2.Len() == 2 {
|
|
if v := list2.At(0).Val(); v != 27 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[0].val = %d; want 27", v)
|
|
}
|
|
if v := list2.At(0).Duo(); v != 26 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[0].duo = %d; want 26", v)
|
|
}
|
|
if v := list2.At(1).Val(); v != 42 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[1].val = %d; want 42", v)
|
|
}
|
|
if v := list2.At(1).Duo(); v != 41 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[1].duo = %d; want 41", v)
|
|
}
|
|
} else {
|
|
t.Errorf("len(HoldsVerTwoDataList.mylist) = %d; want 2", list2.Len())
|
|
}
|
|
}()
|
|
}
|
|
|
|
func TestV1DataVersioningEmptyToBigger(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(t, "HoldsVerEmptyList", "(mylist = [(),()])", []byte{
|
|
0, 0, 0, 0, 3, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 7, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
remsg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
|
|
reHolder1, err := air.ReadRootHoldsVerOneDataList(remsg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootHoldsVerOneDataList:", err)
|
|
}
|
|
list1, err := reHolder1.Mylist()
|
|
if err != nil {
|
|
t.Fatal("HoldsVerOneDataList.mylist:", err)
|
|
}
|
|
if list1.Len() == 2 {
|
|
if v := list1.At(0).Val(); v != 0 {
|
|
t.Errorf("HoldsVerOneDataList.mylist[0].val = %d; want 0", v)
|
|
}
|
|
if v := list1.At(1).Val(); v != 0 {
|
|
t.Errorf("HoldsVerOneDataList.mylist[1].val = %d; want 0", v)
|
|
}
|
|
} else {
|
|
t.Errorf("len(HoldsVerOneDataList.mylist) = %d; want 2", list1.Len())
|
|
}
|
|
|
|
reHolder2, err := air.ReadRootHoldsVerTwoDataList(remsg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootHoldsVerOneDataList:", err)
|
|
}
|
|
list2, err := reHolder2.Mylist()
|
|
if err != nil {
|
|
t.Fatal("HoldsVerOneDataList.mylist:", err)
|
|
}
|
|
if list2.Len() == 2 {
|
|
if v := list2.At(0).Val(); v != 0 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[0].val = %d; want 0", v)
|
|
}
|
|
if v := list2.At(0).Duo(); v != 0 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[0].duo = %d; want 0", v)
|
|
}
|
|
if v := list2.At(1).Val(); v != 0 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[1].val = %d; want 0", v)
|
|
}
|
|
if v := list2.At(1).Duo(); v != 0 {
|
|
t.Errorf("HoldsVerTwoDataList.mylist[1].duo = %d; want 0", v)
|
|
}
|
|
} else {
|
|
t.Errorf("len(HoldsVerTwoDataList.mylist) = %d; want 2", list2.Len())
|
|
}
|
|
}
|
|
|
|
func TestDataVersioningZeroPointersToMore(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(t, "HoldsVerEmptyList", "(mylist = [(),()])", []byte{
|
|
0, 0, 0, 0, 3, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 7, 0, 0, 0,
|
|
8, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
remsg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
reHolder, err := air.ReadRootHoldsVerTwoTwoList(remsg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootHoldsVerTwoTwoList:", err)
|
|
}
|
|
list22, err := reHolder.Mylist()
|
|
if err != nil {
|
|
t.Fatal("HoldsVerTwoTwoList.mylist:", err)
|
|
}
|
|
if list22.Len() != 2 {
|
|
t.Errorf("len(HoldsVerTwoTwoList.mylist) = %d; want 2", list22.Len())
|
|
}
|
|
for i := 0; i < list22.Len(); i++ {
|
|
ele := list22.At(i)
|
|
if val := ele.Val(); val != 0 {
|
|
t.Errorf("HoldsVerTwoTwoList.mylist[%d].val = %d; want 0", i, val)
|
|
}
|
|
if duo := ele.Duo(); duo != 0 {
|
|
t.Errorf("HoldsVerTwoTwoList.mylist[%d].duo = %d; want 0", i, duo)
|
|
}
|
|
if ptr1, err := ele.Ptr1(); err != nil {
|
|
t.Errorf("HoldsVerTwoTwoList.mylist[%d].ptr1: %v", i, err)
|
|
} else if capnp.IsValid(ptr1) {
|
|
t.Errorf("HoldsVerTwoTwoList.mylist[%d].ptr1 = %#v; want invalid (nil)", i, ptr1)
|
|
}
|
|
if ptr2, err := ele.Ptr2(); err != nil {
|
|
t.Errorf("HoldsVerTwoTwoList.mylist[%d].ptr2: %v", i, err)
|
|
} else if capnp.IsValid(ptr2) {
|
|
t.Errorf("HoldsVerTwoTwoList.mylist[%d].ptr2 = %#v; want invalid (nil)", i, ptr2)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDataVersioningZeroPointersToTwo(t *testing.T) {
|
|
t.Parallel()
|
|
in := mustEncodeTestMessage(
|
|
t,
|
|
"HoldsVerTwoTwoList",
|
|
`(mylist = [
|
|
(val = 27, duo = 26, ptr1 = (val = 25), ptr2 = (val = 23)),
|
|
(val = 42, duo = 41, ptr1 = (val = 40), ptr2 = (val = 38))])`,
|
|
[]byte{
|
|
0, 0, 0, 0, 15, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
|
1, 0, 0, 0, 71, 0, 0, 0,
|
|
8, 0, 0, 0, 2, 0, 2, 0,
|
|
27, 0, 0, 0, 0, 0, 0, 0,
|
|
26, 0, 0, 0, 0, 0, 0, 0,
|
|
20, 0, 0, 0, 1, 0, 0, 0,
|
|
20, 0, 0, 0, 1, 0, 0, 0,
|
|
42, 0, 0, 0, 0, 0, 0, 0,
|
|
41, 0, 0, 0, 0, 0, 0, 0,
|
|
12, 0, 0, 0, 1, 0, 0, 0,
|
|
12, 0, 0, 0, 1, 0, 0, 0,
|
|
25, 0, 0, 0, 0, 0, 0, 0,
|
|
23, 0, 0, 0, 0, 0, 0, 0,
|
|
40, 0, 0, 0, 0, 0, 0, 0,
|
|
38, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
remsg, err := capnp.Unmarshal(in)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
|
|
// 0 pointers
|
|
func() {
|
|
reHolder, err := air.ReadRootHoldsVerEmptyList(remsg)
|
|
if err != nil {
|
|
t.Error("ReadRootHoldsVerEmptyList:", err)
|
|
return
|
|
}
|
|
list, err := reHolder.Mylist()
|
|
if err != nil {
|
|
t.Error("HoldsVerEmptyList.mylist:", err)
|
|
return
|
|
}
|
|
if list.Len() != 2 {
|
|
t.Errorf("len(HoldsVerEmptyList.mylist) = %d; want 2", list.Len())
|
|
}
|
|
}()
|
|
|
|
// 1 pointer
|
|
func() {
|
|
holder, err := air.ReadRootHoldsVerOnePtrList(remsg)
|
|
if err != nil {
|
|
t.Error("ReadRootHoldsVerOnePtrList:", err)
|
|
return
|
|
}
|
|
list, err := holder.Mylist()
|
|
if err != nil {
|
|
t.Error("HoldsVerOnePtrList.mylist:", err)
|
|
return
|
|
}
|
|
if list.Len() != 2 {
|
|
t.Errorf("len(HoldsVerOnePtrList.mylist) = %d; want 2", list.Len())
|
|
return
|
|
}
|
|
check := func(i int, val int16) {
|
|
p, err := list.At(i).Ptr()
|
|
if err != nil {
|
|
t.Errorf("HoldsVerOnePtrList.mylist[%d].ptr: %v", i, err)
|
|
return
|
|
}
|
|
if p.Val() != val {
|
|
t.Errorf("HoldsVerOnePtrList.mylist[%d].ptr.val = %d; want %d", i, p.Val(), val)
|
|
}
|
|
}
|
|
check(0, 25)
|
|
check(1, 40)
|
|
}()
|
|
|
|
// 2 pointers
|
|
func() {
|
|
holder, err := air.ReadRootHoldsVerTwoTwoPlus(remsg)
|
|
if err != nil {
|
|
t.Error("ReadRootHoldsVerTwoTwoPlus:", err)
|
|
return
|
|
}
|
|
list, err := holder.Mylist()
|
|
if err != nil {
|
|
t.Error("HoldsVerTwoTwoPlus.mylist:", err)
|
|
return
|
|
}
|
|
if list.Len() != 2 {
|
|
t.Errorf("len(HoldsVerTwoTwoPlus.mylist) = %d; want 2", list.Len())
|
|
return
|
|
}
|
|
check := func(i int, val1, val2 int16) {
|
|
if p, err := list.At(i).Ptr1(); err != nil {
|
|
t.Errorf("HoldsVerTwoTwoPlus.mylist[%d].ptr1: %v", i, err)
|
|
} else if p.Val() != val1 {
|
|
t.Errorf("HoldsVerTwoTwoPlus.mylist[%d].ptr1.val = %d; want %d", i, p.Val(), val1)
|
|
}
|
|
if p, err := list.At(i).Ptr2(); err != nil {
|
|
t.Errorf("HoldsVerTwoTwoPlus.mylist[%d].ptr2: %v", i, err)
|
|
} else if p.Val() != val2 {
|
|
t.Errorf("HoldsVerTwoTwoPlus.mylist[%d].ptr2.val = %d; want %d", i, p.Val(), val2)
|
|
}
|
|
}
|
|
check(0, 25, 23)
|
|
check(1, 40, 38)
|
|
}()
|
|
}
|
|
|
|
func TestVoidUnionSetters(t *testing.T) {
|
|
t.Parallel()
|
|
want := mustEncodeTestMessage(t, "VoidUnion", "(b = void)", []byte{
|
|
0, 0, 0, 0, 2, 0, 0, 0,
|
|
0, 0, 0, 0, 1, 0, 0, 0,
|
|
1, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
msg, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
voidUnion, err := air.NewRootVoidUnion(seg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
voidUnion.SetB()
|
|
|
|
act, err := msg.Marshal()
|
|
if err != nil {
|
|
t.Fatal("msg.Marshal():", err)
|
|
}
|
|
if !bytes.Equal(act, want) {
|
|
t.Errorf("msg.Marshal() =\n%s\n; want:\n%s", hex.Dump(act), hex.Dump(want))
|
|
}
|
|
}
|
|
|
|
func TestReadDefaults(t *testing.T) {
|
|
t.Parallel()
|
|
data := mustEncodeTestMessage(t, "Defaults", "()", []byte{
|
|
0, 0, 0, 0, 5, 0, 0, 0,
|
|
0, 0, 0, 0, 2, 0, 2, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
})
|
|
|
|
msg, err := capnp.Unmarshal(data)
|
|
if err != nil {
|
|
t.Fatal("Unmarshal:", err)
|
|
}
|
|
d, err := air.ReadRootDefaults(msg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootDefaults:", err)
|
|
}
|
|
|
|
if s, err := d.Text(); err != nil {
|
|
t.Errorf("d.Text() error: %v", err)
|
|
} else if s != "foo" {
|
|
t.Errorf("d.Text() = %q; want \"foo\"", s)
|
|
}
|
|
if b, err := d.TextBytes(); err != nil {
|
|
t.Errorf("d.TextBytes() error: %v", err)
|
|
} else if !bytes.Equal(b, []byte("foo")) {
|
|
t.Errorf("d.TextBytes() = %q; want \"foo\"", b)
|
|
}
|
|
if b, err := d.Data(); err != nil {
|
|
t.Errorf("d.Data() error: %v", err)
|
|
} else if !bytes.Equal(b, []byte("bar")) {
|
|
t.Errorf("d.Data() = %q; want \"bar\"", b)
|
|
}
|
|
if f := d.Float(); f != 3.14 {
|
|
t.Errorf("d.Float() = %g; want 3.14", f)
|
|
}
|
|
if i := d.Int(); i != -123 {
|
|
t.Errorf("d.Int() = %d; want -123", i)
|
|
}
|
|
if i := d.Uint(); i != 42 {
|
|
t.Errorf("d.Uint() = %d; want 42", i)
|
|
}
|
|
}
|
|
|
|
type A struct {
|
|
Name string
|
|
BirthDay time.Time
|
|
Phone string
|
|
Siblings int
|
|
Spouse bool
|
|
Money float64
|
|
}
|
|
|
|
func generateA(r *rand.Rand) *A {
|
|
return &A{
|
|
Name: randString(r, 16),
|
|
BirthDay: time.Unix(r.Int63(), 0),
|
|
Phone: randString(r, 10),
|
|
Siblings: r.Intn(5),
|
|
Spouse: r.Intn(2) == 1,
|
|
Money: r.Float64(),
|
|
}
|
|
}
|
|
|
|
func unmarshalA(aa air.BenchmarkA) A {
|
|
name, _ := aa.NameBytes()
|
|
phone, _ := aa.PhoneBytes()
|
|
return A{
|
|
Name: unsafeBytesToString(name),
|
|
BirthDay: time.Unix(aa.BirthDay(), 0),
|
|
Phone: unsafeBytesToString(phone),
|
|
Siblings: int(aa.Siblings()),
|
|
Spouse: aa.Spouse(),
|
|
Money: aa.Money(),
|
|
}
|
|
}
|
|
|
|
func (a *A) fill(aa air.BenchmarkA) {
|
|
aa.SetName(a.Name)
|
|
aa.SetBirthDay(a.BirthDay.Unix())
|
|
aa.SetPhone(a.Phone)
|
|
aa.SetSiblings(int32(a.Siblings))
|
|
aa.SetSpouse(a.Spouse)
|
|
aa.SetMoney(a.Money)
|
|
}
|
|
|
|
func randString(r *rand.Rand, n int) string {
|
|
b := make([]byte, (n+1)/2)
|
|
// Go 1.6 adds a Rand.Read method, but since we want to be compatible with Go 1.4...
|
|
for i := range b {
|
|
b[i] = byte(r.Intn(255))
|
|
}
|
|
return hex.EncodeToString(b)[:n]
|
|
}
|
|
|
|
func unsafeBytesToString(b []byte) string {
|
|
slice := *(*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|
hdr := reflect.StringHeader{Data: slice.Data, Len: slice.Len}
|
|
return *(*string)(unsafe.Pointer(&hdr))
|
|
}
|
|
|
|
func BenchmarkMarshal(b *testing.B) {
|
|
r := rand.New(rand.NewSource(12345))
|
|
data := make([]*A, 1000)
|
|
for i := range data {
|
|
data[i] = generateA(r)
|
|
}
|
|
arena := make([]byte, 0, 512)
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
a := data[r.Intn(len(data))]
|
|
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(arena[:0]))
|
|
root, _ := air.NewRootBenchmarkA(seg)
|
|
a.fill(root)
|
|
msg.Marshal()
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshal(b *testing.B) {
|
|
r := rand.New(rand.NewSource(12345))
|
|
data := make([][]byte, 1000)
|
|
for i := range data {
|
|
a := generateA(r)
|
|
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
root, _ := air.NewRootBenchmarkA(seg)
|
|
a.fill(root)
|
|
data[i], _ = msg.Marshal()
|
|
}
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
msg, _ := capnp.Unmarshal(data[r.Intn(len(data))])
|
|
a, _ := air.ReadRootBenchmarkA(msg)
|
|
unmarshalA(a)
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshal_Reuse(b *testing.B) {
|
|
r := rand.New(rand.NewSource(12345))
|
|
data := make([][]byte, 1000)
|
|
for i := range data {
|
|
a := generateA(r)
|
|
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
root, _ := air.NewRootBenchmarkA(seg)
|
|
a.fill(root)
|
|
data[i], _ = msg.Marshal()
|
|
}
|
|
msg := new(capnp.Message)
|
|
ta := new(testArena)
|
|
arena := capnp.Arena(ta)
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
*ta = testArena(data[r.Intn(len(data))][8:])
|
|
msg.Reset(arena)
|
|
a, _ := air.ReadRootBenchmarkA(msg)
|
|
unmarshalA(a)
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecode(b *testing.B) {
|
|
var buf bytes.Buffer
|
|
|
|
r := rand.New(rand.NewSource(12345))
|
|
enc := capnp.NewEncoder(&buf)
|
|
count := 10000
|
|
|
|
for i := 0; i < count; i++ {
|
|
a := generateA(r)
|
|
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
root, _ := air.NewRootBenchmarkA(seg)
|
|
a.fill(root)
|
|
enc.Encode(msg)
|
|
}
|
|
|
|
blob := buf.Bytes()
|
|
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(buf.Len()))
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
dec := capnp.NewDecoder(bytes.NewReader(blob))
|
|
|
|
for {
|
|
msg, err := dec.Decode()
|
|
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
_, err = air.ReadRootBenchmarkA(msg)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkDecode_Reuse(b *testing.B) {
|
|
var buf bytes.Buffer
|
|
|
|
r := rand.New(rand.NewSource(12345))
|
|
enc := capnp.NewEncoder(&buf)
|
|
count := 10000
|
|
|
|
for i := 0; i < count; i++ {
|
|
a := generateA(r)
|
|
msg, seg, _ := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
root, _ := air.NewRootBenchmarkA(seg)
|
|
a.fill(root)
|
|
enc.Encode(msg)
|
|
}
|
|
|
|
blob := buf.Bytes()
|
|
|
|
b.ReportAllocs()
|
|
b.SetBytes(int64(buf.Len()))
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
dec := capnp.NewDecoder(bytes.NewReader(blob))
|
|
dec.ReuseBuffer()
|
|
|
|
for {
|
|
msg, err := dec.Decode()
|
|
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
_, err = air.ReadRootBenchmarkA(msg)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type testArena []byte
|
|
|
|
func (ta testArena) NumSegments() int64 {
|
|
return 1
|
|
}
|
|
|
|
func (ta testArena) Data(id capnp.SegmentID) ([]byte, error) {
|
|
if id != 0 {
|
|
return nil, errors.New("test arena: requested non-zero segment")
|
|
}
|
|
return []byte(ta), nil
|
|
}
|
|
|
|
func (ta testArena) Allocate(capnp.Size, map[capnp.SegmentID]*capnp.Segment) (capnp.SegmentID, []byte, error) {
|
|
return 0, nil, errors.New("test arena: can't allocate")
|
|
}
|
|
|
|
func TestPointerTraverseDefense(t *testing.T) {
|
|
t.Parallel()
|
|
const limit = 128
|
|
msg := &capnp.Message{
|
|
Arena: capnp.SingleSegment([]byte{
|
|
0, 0, 0, 0, 1, 0, 0, 0, // root 1-word struct pointer to next word
|
|
0, 0, 0, 0, 0, 0, 0, 0, // struct's data
|
|
}),
|
|
TraverseLimit: limit * 8,
|
|
}
|
|
|
|
for i := 0; i < limit; i++ {
|
|
_, err := msg.RootPtr()
|
|
if err != nil {
|
|
t.Fatalf("iteration %d RootPtr: %v", i, err)
|
|
}
|
|
}
|
|
|
|
if _, err := msg.RootPtr(); err == nil {
|
|
t.Fatalf("deref %d did not fail as expected", limit+1)
|
|
}
|
|
}
|
|
|
|
func TestPointerDepthDefense(t *testing.T) {
|
|
t.Parallel()
|
|
const limit = 64
|
|
msg := &capnp.Message{
|
|
Arena: capnp.SingleSegment([]byte{
|
|
0, 0, 0, 0, 0, 0, 1, 0, // root 1-pointer struct pointer to next word
|
|
0xfc, 0xff, 0xff, 0xff, 0, 0, 1, 0, // root struct pointer that points back to itself
|
|
}),
|
|
DepthLimit: limit,
|
|
}
|
|
root, err := msg.Root()
|
|
if err != nil {
|
|
t.Fatal("Root:", err)
|
|
}
|
|
|
|
curr := capnp.ToStruct(root)
|
|
if !capnp.IsValid(curr) {
|
|
t.Fatal("Root is not a struct")
|
|
}
|
|
for i := 0; i < limit-1; i++ {
|
|
p, err := curr.Pointer(0)
|
|
if err != nil {
|
|
t.Fatalf("deref %d fail: %v", i+1, err)
|
|
}
|
|
if !capnp.IsValid(p) {
|
|
t.Fatalf("deref %d is invalid", i+1)
|
|
}
|
|
curr = capnp.ToStruct(p)
|
|
if !capnp.IsValid(curr) {
|
|
t.Fatalf("deref %d is not a struct", i+1)
|
|
}
|
|
}
|
|
|
|
_, err = curr.Pointer(0)
|
|
if err == nil {
|
|
t.Fatalf("deref %d did not fail as expected", limit)
|
|
}
|
|
}
|
|
|
|
func TestPointerDepthDefenseAcrossStructsAndLists(t *testing.T) {
|
|
t.Parallel()
|
|
const limit = 63
|
|
msg := &capnp.Message{
|
|
Arena: capnp.SingleSegment([]byte{
|
|
0, 0, 0, 0, 0, 0, 1, 0, // root 1-pointer struct pointer to next word
|
|
0x01, 0, 0, 0, 0x0e, 0, 0, 0, // list pointer to 1-element list of pointer (next word)
|
|
0xf8, 0xff, 0xff, 0xff, 0, 0, 1, 0, // struct pointer to previous word
|
|
}),
|
|
DepthLimit: limit,
|
|
}
|
|
|
|
toStruct := func(p capnp.Pointer, err error) (capnp.Struct, error) {
|
|
if err != nil {
|
|
return capnp.Struct{}, err
|
|
}
|
|
if !capnp.IsValid(p) {
|
|
return capnp.Struct{}, errors.New("invalid pointer")
|
|
}
|
|
s := capnp.ToStruct(p)
|
|
if !capnp.IsValid(s) {
|
|
return capnp.Struct{}, errors.New("not a struct")
|
|
}
|
|
return s, nil
|
|
}
|
|
toList := func(p capnp.Pointer, err error) (capnp.List, error) {
|
|
if err != nil {
|
|
return capnp.List{}, err
|
|
}
|
|
if !capnp.IsValid(p) {
|
|
return capnp.List{}, errors.New("invalid pointer")
|
|
}
|
|
l := capnp.ToList(p)
|
|
if !capnp.IsValid(l) {
|
|
return capnp.List{}, errors.New("not a list")
|
|
}
|
|
return l, nil
|
|
}
|
|
curr, err := toStruct(msg.Root())
|
|
if err != nil {
|
|
t.Fatal("Root:", err)
|
|
}
|
|
for i := limit; i > 2; {
|
|
l, err := toList(curr.Pointer(0))
|
|
if err != nil {
|
|
t.Fatalf("deref %d (for list): %v", limit-i+1, err)
|
|
}
|
|
i--
|
|
curr, err = toStruct(capnp.PointerList{List: l}.At(0))
|
|
if err != nil {
|
|
t.Fatalf("deref %d (for struct): %v", limit-i+1, err)
|
|
}
|
|
i--
|
|
}
|
|
|
|
_, err = curr.Pointer(0)
|
|
if err == nil {
|
|
t.Fatalf("deref %d did not fail as expected", limit)
|
|
}
|
|
}
|
|
|
|
func TestHasPointerInUnion(t *testing.T) {
|
|
t.Parallel()
|
|
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal("NewMessage:", err)
|
|
}
|
|
craft, err := air.NewRootAircraft(seg)
|
|
if err != nil {
|
|
t.Fatal("NewRootAircraft:", err)
|
|
}
|
|
t.Log("NewB737")
|
|
_, err = craft.NewB737()
|
|
if err != nil {
|
|
t.Fatal("NewB737:", err)
|
|
}
|
|
|
|
// These pointers are at the same offset.
|
|
if !craft.HasB737() {
|
|
t.Errorf("HasB737 = false; want true")
|
|
}
|
|
if craft.HasA320() {
|
|
t.Errorf("HasA320 = true; want false")
|
|
}
|
|
}
|
|
|
|
func TestSetNilBlob(t *testing.T) {
|
|
t.Parallel()
|
|
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal("NewMessage:", err)
|
|
}
|
|
z, err := air.NewRootZ(seg)
|
|
if err != nil {
|
|
t.Fatal("NewRootZ:", err)
|
|
}
|
|
if err := z.SetBlob(nil); err != nil {
|
|
t.Fatal("z.SetBlob(nil):", err)
|
|
}
|
|
|
|
if z.HasBlob() {
|
|
t.Error("z.HasBlob() = true; want false")
|
|
}
|
|
blob, err := z.Blob()
|
|
if err != nil {
|
|
t.Errorf("z.Blob(): %v", err)
|
|
}
|
|
if blob != nil {
|
|
t.Errorf("z.Blob() = %v; want nil", blob)
|
|
}
|
|
}
|
|
|
|
func TestSetEmptyText(t *testing.T) {
|
|
t.Parallel()
|
|
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal("NewMessage:", err)
|
|
}
|
|
z, err := air.NewRootZ(seg)
|
|
if err != nil {
|
|
t.Fatal("NewRootZ:", err)
|
|
}
|
|
if err := z.SetText(""); err != nil {
|
|
t.Fatal("z.SetText(\"\"):", err)
|
|
}
|
|
|
|
if z.HasText() {
|
|
t.Error("z.HasText() = true; want false")
|
|
}
|
|
text, err := z.Text()
|
|
if err != nil {
|
|
t.Errorf("z.Text(): %v", err)
|
|
}
|
|
if text != "" {
|
|
t.Errorf("z.Text() = %q; want \"\"", text)
|
|
}
|
|
b, err := z.TextBytes()
|
|
if err != nil {
|
|
t.Errorf("z.TextBytes(): %v", err)
|
|
}
|
|
if b != nil {
|
|
t.Errorf("z.TextBytes() = %v; want nil", b)
|
|
}
|
|
}
|
|
|
|
func TestSetNilBlobWithDefault(t *testing.T) {
|
|
t.Parallel()
|
|
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal("NewMessage:", err)
|
|
}
|
|
d, err := air.NewRootDefaults(seg)
|
|
if err != nil {
|
|
t.Fatal("NewRootDefaults:", err)
|
|
}
|
|
if err := d.SetData(nil); err != nil {
|
|
t.Fatal("d.SetData(nil):", err)
|
|
}
|
|
|
|
if !d.HasData() {
|
|
t.Error("d.HasData() = false; want true")
|
|
}
|
|
blob, err := d.Data()
|
|
if err != nil {
|
|
t.Errorf("d.Data(): %v", err)
|
|
}
|
|
if len(blob) != 0 {
|
|
t.Errorf("d.Data() = %v; want zero length", blob)
|
|
}
|
|
// Specifically not checking for nil. Anything zero-length is appropriate here.
|
|
}
|
|
|
|
func TestSetEmptyTextWithDefault(t *testing.T) {
|
|
t.Parallel()
|
|
_, seg, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
|
if err != nil {
|
|
t.Fatal("NewMessage:", err)
|
|
}
|
|
d, err := air.NewRootDefaults(seg)
|
|
if err != nil {
|
|
t.Fatal("NewRootDefaults:", err)
|
|
}
|
|
if err := d.SetText(""); err != nil {
|
|
t.Fatal("d.SetData(\"\"):", err)
|
|
}
|
|
|
|
if !d.HasText() {
|
|
t.Error("d.HasText() = false; want true")
|
|
}
|
|
text, err := d.Text()
|
|
if err != nil {
|
|
t.Errorf("d.Text(): %v", err)
|
|
}
|
|
if text != "" {
|
|
t.Errorf("d.Text() = %v; want zero length", text)
|
|
}
|
|
b, err := d.TextBytes()
|
|
if err != nil {
|
|
t.Errorf("d.TextBytes(): %v", err)
|
|
}
|
|
if len(b) != 0 {
|
|
t.Errorf("d.TextBytes() = %v; want zero length", b)
|
|
}
|
|
}
|
|
|
|
func TestFuzzedListOutOfBounds(t *testing.T) {
|
|
t.Parallel()
|
|
msg := &capnp.Message{
|
|
Arena: capnp.SingleSegment([]byte(
|
|
"\x00\x00\x00\x00\x03\x00\x01\x00\x0f\x000000000000" +
|
|
"000000000000\x01\x00\x00\x00\x13\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00")),
|
|
}
|
|
z, err := air.ReadRootZ(msg)
|
|
if err != nil {
|
|
t.Fatal("ReadRootZ:", err)
|
|
}
|
|
if z.Which() != air.Z_Which_f64vec {
|
|
t.Fatalf("z.Which() = %v; want Z_Which_f64vec", z.Which())
|
|
}
|
|
v, err := z.F64vec()
|
|
if err != nil {
|
|
t.Fatal("z.F64vec:", err)
|
|
}
|
|
for i := 0; i < v.Len(); i++ {
|
|
// This should not crash.
|
|
t.Logf("v.At(%d); v.Len() = %d", i, v.Len())
|
|
v.At(i)
|
|
}
|
|
}
|
|
|
|
func benchmarkGrowth(b *testing.B, newArena func() capnp.Arena) {
|
|
const (
|
|
fieldValue = "1234567" // carefully chosen to be word-padded
|
|
|
|
rootMessageOverhead = 8 * 3 // root pointer, Document struct, composite list tag
|
|
perFieldOverhead = 8 * 2 // Field struct, fieldValue + "\0"
|
|
numElements = 64 * 1024
|
|
totalSize = rootMessageOverhead + perFieldOverhead*numElements
|
|
)
|
|
b.SetBytes(totalSize)
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
_, seg, err := capnp.NewMessage(newArena())
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
doc, err := air.NewRootAllocBenchmark(seg)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
d, err := doc.NewFields(numElements)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
for j := 0; j < numElements; j++ {
|
|
if err := d.At(j).SetStringValue(fieldValue); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkGrowth_SingleSegment(b *testing.B) {
|
|
benchmarkGrowth(b, func() capnp.Arena { return capnp.SingleSegment(nil) })
|
|
}
|
|
|
|
func BenchmarkGrowth_MultiSegment(b *testing.B) {
|
|
benchmarkGrowth(b, func() capnp.Arena { return capnp.MultiSegment(nil) })
|
|
}
|
|
|
|
func benchmarkSmallMessage(b *testing.B, newArena func() capnp.Arena) {
|
|
const fieldValue = "1234567" // carefully chosen to be word-padded
|
|
b.SetBytes(8 * 9)
|
|
b.ReportAllocs()
|
|
for i := 0; i < b.N; i++ {
|
|
_, seg, err := capnp.NewMessage(newArena())
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
root, err := capnp.NewRootStruct(seg, capnp.ObjectSize{PointerCount: 2})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
sub1, err := capnp.NewStruct(root.Segment(), capnp.ObjectSize{PointerCount: 1})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if err := root.SetPtr(0, sub1.ToPtr()); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
text, err := capnp.NewText(sub1.Segment(), fieldValue)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if err := sub1.SetPtr(0, text.ToPtr()); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
sub2, err := capnp.NewStruct(root.Segment(), capnp.ObjectSize{DataSize: 32})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if err := root.SetPtr(0, sub2.ToPtr()); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkSmallMessage_SingleSegment(b *testing.B) {
|
|
benchmarkSmallMessage(b, func() capnp.Arena { return capnp.SingleSegment(nil) })
|
|
}
|
|
|
|
func BenchmarkSmallMessage_MultiSegment(b *testing.B) {
|
|
benchmarkSmallMessage(b, func() capnp.Arena { return capnp.MultiSegment(nil) })
|
|
}
|