Example #1
0
// Find returns the node for the given ID.
func (m *Map) Find(id uint64) (schema.Node, error) {
	if n := m.nodes[id]; n.IsValid() {
		return n, nil
	}
	data, err := m.registry().Find(id)
	if err != nil {
		return schema.Node{}, err
	}
	msg, err := capnp.Unmarshal(data)
	if err != nil {
		return schema.Node{}, err
	}
	req, err := schema.ReadRootCodeGeneratorRequest(msg)
	if err != nil {
		return schema.Node{}, err
	}
	nodes, err := req.Nodes()
	if err != nil {
		return schema.Node{}, err
	}
	if m.nodes == nil {
		m.nodes = make(map[uint64]schema.Node)
	}
	for i := 0; i < nodes.Len(); i++ {
		n := nodes.At(i)
		m.nodes[n.Id()] = n
	}
	return m.nodes[id], nil
}
Example #2
0
func TestDefaultFind(t *testing.T) {
	if s := schemas.Find(0xdeadbeef); s != nil {
		t.Errorf("schemas.Find(0xdeadbeef) = %d-byte slice; want nil", len(s))
	}
	s := schemas.Find(capnp.Package)
	if s == nil {
		t.Fatalf("schemas.Find(%#x) = nil", capnp.Package)
	}
	msg, err := capnp.Unmarshal(s)
	if err != nil {
		t.Fatalf("capnp.Unmarshal(schemas.Find(%#x)) error: %v", capnp.Package, err)
	}
	req, err := schema.ReadRootCodeGeneratorRequest(msg)
	if err != nil {
		t.Fatalf("ReadRootCodeGeneratorRequest error: %v", err)
	}
	nodes, err := req.Nodes()
	if err != nil {
		t.Fatalf("req.Nodes() error: %v", err)
	}
	for i := 0; i < nodes.Len(); i++ {
		n := nodes.At(i)
		if n.Id() == capnp.Package {
			// Found
			if n.Which() != schema.Node_Which_annotation {
				t.Errorf("found node %#x which = %v; want annotation", capnp.Package, n.Which())
			}
			return
		}
	}
	t.Fatalf("could not find node %#x in registry", capnp.Package)
}
func mustReadGeneratorRequest(t *testing.T, name string) schema.CodeGeneratorRequest {
	data := mustReadTestFile(t, name)
	msg, err := capnp.Unmarshal(data)
	if err != nil {
		t.Fatalf("Unmarshaling %s: %v", name, err)
	}
	req, err := schema.ReadRootCodeGeneratorRequest(msg)
	if err != nil {
		t.Fatalf("Reading code generator request %s: %v", name, err)
	}
	return req
}
Example #4
0
func main() {
	var opts genoptions
	flag.BoolVar(&opts.promises, "promises", true, "generate code for promises")
	flag.BoolVar(&opts.schemas, "schemas", true, "embed schema information in generated code")
	flag.BoolVar(&opts.structStrings, "structstrings", true, "generate String() methods for structs (-schemas must be true)")
	flag.Parse()

	msg, err := capnp.NewDecoder(os.Stdin).Decode()
	if err != nil {
		fmt.Fprintln(os.Stderr, "capnpc-go: reading input:", err)
		os.Exit(1)
	}
	req, err := schema.ReadRootCodeGeneratorRequest(msg)
	if err != nil {
		fmt.Fprintln(os.Stderr, "capnpc-go: reading input:", err)
		os.Exit(1)
	}
	nodes, err := buildNodeMap(req)
	if err != nil {
		fmt.Fprintln(os.Stderr, "capnpc-go:", err)
		os.Exit(1)
	}
	success := true
	reqFiles, _ := req.RequestedFiles()
	for i := 0; i < reqFiles.Len(); i++ {
		reqf := reqFiles.At(i)
		err := generateFile(reqf, nodes, opts)
		if err != nil {
			fname, _ := reqf.Filename()
			fmt.Fprintf(os.Stderr, "capnpc-go: generating %s: %v\n", fname, err)
			success = false
		}
	}
	if !success {
		os.Exit(1)
	}
}
Example #5
0
func TestEncode(t *testing.T) {
	tests := []struct {
		constID uint64
		text    string
	}{
		{0xc0b634e19e5a9a4e, `(key = "42", value = (int32 = -123))`},
		{0x967c8fe21790b0fb, `(key = "float", value = (float64 = 3.14))`},
		{0xdf35cb2e1f5ea087, `(key = "bool", value = (bool = false))`},
		{0xb167974479102805, `(map = [(key = "foo", value = (void = void)), (key = "bar", value = (void = void))])`},
		{0x81fdbfdc91779421, `(map = [])`},
		{0x8e85252144f61858, `(data = "Hi\xde\xad\xbe\xef\xca\xfe")`},
		{0xc21398a8474837ba, `(voidList = [void, void])`},
		{0xde82c2eeb3a4b07c, `(boolList = [true, false, true, false])`},
		{0xf9e3ffc179272aa2, `(int8List = [1, -2, 3])`},
		{0xfc421b96ec6ad2b6, `(int64List = [1, -2, 3])`},
		{0xb3034b89d02775a5, `(uint8List = [255, 0, 1])`},
		{0x9246c307e46ad03b, `(uint64List = [1, 2, 3])`},
		{0xd012128a1a9cb7fc, `(float32List = [0.5, 3.14, -2])`},
		{0xf16c386c66d492e2, `(textList = ["foo", "bar", "baz"])`},
		{0xe14f4d42aa55de8c, `(dataList = ["\xde\xad\xbe\xef", "\xca\xfe"])`},
		{0xe88c91698f7f0b73, `(cheese = gouda)`},
		{0x9c51b843b337490b, `(cheeseList = [gouda, cheddar])`},
		{0x81e2aadb8bfb237b, `(matrix = [[1, 2, 3], [4, 5, 6]])`},
	}

	data, err := readTestFile("txt.capnp.out")
	if err != nil {
		t.Fatal(err)
	}
	reg := new(schemas.Registry)
	err = reg.Register(&schemas.Schema{
		Bytes: data,
		Nodes: []uint64{
			0x8df8bc5abdc060a6,
			0xd3602730c572a43b,
		},
	})
	if err != nil {
		t.Fatalf("Adding to registry: %v", err)
	}
	msg, err := capnp.Unmarshal(data)
	if err != nil {
		t.Fatal("Unmarshaling txt.capnp.out:", err)
	}
	req, err := schema.ReadRootCodeGeneratorRequest(msg)
	if err != nil {
		t.Fatal("Reading code generator request txt.capnp.out:", err)
	}
	nodes, err := req.Nodes()
	if err != nil {
		t.Fatal(err)
	}
	nodeMap := make(map[uint64]schema.Node, nodes.Len())
	for i := 0; i < nodes.Len(); i++ {
		n := nodes.At(i)
		nodeMap[n.Id()] = n
	}

	for _, test := range tests {
		c := nodeMap[test.constID]
		if !c.IsValid() {
			t.Errorf("Can't find node %#x; skipping", test.constID)
			continue
		}
		dn, _ := c.DisplayName()
		if c.Which() != schema.Node_Which_const {
			t.Errorf("%s @%#x is a %v, not const; skipping", dn, test.constID, c.Which())
			continue
		}

		typ, err := c.Const().Type()
		if err != nil {
			t.Errorf("(%s @%#x).const.type: %v", dn, test.constID, err)
			continue
		}
		if typ.Which() != schema.Type_Which_structType {
			t.Errorf("(%s @%#x).const.type is a %v; want struct", dn, test.constID, typ.Which())
			continue
		}
		tid := typ.StructType().TypeId()

		v, err := c.Const().Value()
		if err != nil {
			t.Errorf("(%s @%#x).const.value: %v", dn, test.constID, err)
			continue
		}
		if v.Which() != schema.Value_Which_structValue {
			t.Errorf("(%s @%#x).const.value is a %v; want struct", dn, test.constID, v.Which())
			continue
		}
		sv, err := v.StructValuePtr()
		if err != nil {
			t.Errorf("(%s @%#x).const.value.struct: %v", dn, test.constID, err)
			continue
		}

		buf := new(bytes.Buffer)
		enc := NewEncoder(buf)
		enc.UseRegistry(reg)
		if err := enc.Encode(tid, sv.Struct()); err != nil {
			t.Errorf("Encode(%#x, (%s @%#x).const.value.struct): %v", tid, dn, test.constID, err)
			continue
		}
		if text := buf.String(); text != test.text {
			t.Errorf("Encode(%#x, (%s @%#x).const.value.struct) = %q; want %q", tid, dn, test.constID, text, test.text)
			continue
		}
	}
}
func TestBuildNodeMap(t *testing.T) {
	tests := []struct {
		name      string
		fileID    uint64
		fileNodes []uint64
	}{
		{
			name:   "go.capnp.out",
			fileID: 0xd12a1c51fedd6c88,
			fileNodes: []uint64{
				0xbea97f1023792be0,
				0xe130b601260e44b5,
				0xc58ad6bd519f935e,
				0xa574b41924caefc7,
				0xc8768679ec52e012,
				0xfa10659ae02f2093,
				0xc2b96012172f8df1,
			},
		},
		{
			name:   "group.capnp.out",
			fileID: 0x83c2b5818e83ab19,
			fileNodes: []uint64{
				0xd119fd352d8ea888, // the struct
				0x822357857e5925d4, // the group
			},
		},
	}
	for _, test := range tests {
		data, err := readTestFile(test.name)
		if err != nil {
			t.Errorf("readTestFile(%q): %v", test.name, err)
			continue
		}
		msg, err := capnp.Unmarshal(data)
		if err != nil {
			t.Errorf("Unmarshaling %s: %v", test.name, err)
			continue
		}
		req, err := schema.ReadRootCodeGeneratorRequest(msg)
		if err != nil {
			t.Errorf("Reading code generator request %s: %v", test.name, err)
			continue
		}
		nodes, err := buildNodeMap(req)
		if err != nil {
			t.Errorf("%s: buildNodeMap: %v", test.name, err)
		}
		f := nodes[test.fileID]
		if f == nil {
			t.Errorf("%s: node map is missing file node @%#x", test.name, test.fileID)
			continue
		}
		if f.Id() != test.fileID {
			t.Errorf("%s: node map has ID @%#x for lookup of @%#x", test.name, f.Id(), test.fileID)
		}

		// Test node.nodes collection
		for _, id := range test.fileNodes {
			found := false
			for _, fn := range f.nodes {
				if fn.Id() == id {
					found = true
					break
				}
			}
			if !found {
				t.Errorf("%s: missing @%#x from file nodes", test.name, id)
			}
		}
		// Test map lookup
		for _, k := range test.fileNodes {
			n := nodes[k]
			if n == nil {
				t.Errorf("%s: missing @%#x from node map", test.name, k)
			}
			if n.Id() != k {
				t.Errorf("%s: node map has ID @%#x for lookup of @%#x", test.name, n.Id(), k)
			}
		}
	}
}
func TestDefineFile(t *testing.T) {
	// Sanity check to make sure codegen produces parseable Go.

	const iterations = 3

	defaultOptions := genoptions{
		promises:      true,
		schemas:       true,
		structStrings: true,
	}
	tests := []struct {
		fileID uint64
		fname  string
		opts   genoptions
	}{
		{0x832bcc6686a26d56, "aircraft.capnp.out", defaultOptions},
		{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
			promises:      false,
			schemas:       false,
			structStrings: false,
		}},
		{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
			promises:      true,
			schemas:       false,
			structStrings: false,
		}},
		{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
			promises:      false,
			schemas:       true,
			structStrings: false,
		}},
		{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
			promises:      true,
			schemas:       true,
			structStrings: false,
		}},
		{0x832bcc6686a26d56, "aircraft.capnp.out", genoptions{
			promises:      false,
			schemas:       true,
			structStrings: true,
		}},
		{0x83c2b5818e83ab19, "group.capnp.out", defaultOptions},
		{0xb312981b2552a250, "rpc.capnp.out", defaultOptions},
		{0xd68755941d99d05e, "scopes.capnp.out", defaultOptions},
		{0xecd50d792c3d9992, "util.capnp.out", defaultOptions},
	}
	for _, test := range tests {
		data, err := readTestFile(test.fname)
		if err != nil {
			t.Errorf("reading %s: %v", test.fname, err)
			continue
		}
		msg, err := capnp.Unmarshal(data)
		if err != nil {
			t.Errorf("Unmarshaling %s: %v", test.fname, err)
			continue
		}
		req, err := schema.ReadRootCodeGeneratorRequest(msg)
		if err != nil {
			t.Errorf("Reading code generator request %s: %v", test.fname, err)
			continue
		}
		nodes, err := buildNodeMap(req)
		if err != nil {
			t.Errorf("buildNodeMap %s: %v", test.fname, err)
			continue
		}
		g := newGenerator(test.fileID, nodes, test.opts)
		if err := g.defineFile(); err != nil {
			t.Errorf("defineFile %s %+v: %v", test.fname, test.opts, err)
			continue
		}
		src := g.generate()
		if _, err := parser.ParseFile(token.NewFileSet(), test.fname+".go", src, 0); err != nil {
			// TODO(light): log src
			t.Errorf("generate %s %+v failed to parse: %v", test.fname, test.opts, err)
		}

		// Generation should be deterministic between runs.
		for i := 0; i < iterations-1; i++ {
			g := newGenerator(test.fileID, nodes, test.opts)
			if err := g.defineFile(); err != nil {
				t.Errorf("defineFile %s %+v [iteration %d]: %v", test.fname, test.opts, i+2, err)
				continue
			}
			src2 := g.generate()
			if !bytes.Equal(src, src2) {
				t.Errorf("defineFile %s %+v [iteration %d] did not match iteration 1: non-deterministic", test.fname, test.opts, i+2)
			}
		}
	}
}