cloudflared-mirror/vendor/zombiezen.com/go/capnproto2/integration_test.go

2397 lines
56 KiB
Go
Raw Normal View History

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) })
}