protogen, cmd/protoc-gen-go: initial commit

Package protogen provides support for writing protoc plugins.
A "plugin" in this case is a program run by protoc to generate output.

The protoc-gen-go command is a protoc plugin to generate Go code.

cmd/protoc-gen-go/golden_test.go is mostly a straight copy from
the golden test in github.com/golang/protobuf.

Change-Id: I332d0df1e4b60bb8cd926320b8721e16b99a4b71
Reviewed-on: https://go-review.googlesource.com/130175
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/protogen/protogen_test.go b/protogen/protogen_test.go
new file mode 100644
index 0000000..1d23cc0
--- /dev/null
+++ b/protogen/protogen_test.go
@@ -0,0 +1,94 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package protogen
+
+import (
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/golang/protobuf/proto"
+	pluginpb "github.com/golang/protobuf/protoc-gen-go/plugin"
+)
+
+func TestFiles(t *testing.T) {
+	gen, err := New(makeRequest(t, "testdata/go_package/no_go_package_import.proto"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	for _, test := range []struct {
+		path         string
+		wantGenerate bool
+	}{
+		{
+			path:         "go_package/no_go_package_import.proto",
+			wantGenerate: true,
+		},
+		{
+			path:         "go_package/no_go_package.proto",
+			wantGenerate: false,
+		},
+	} {
+		f, ok := gen.FileByName(test.path)
+		if !ok {
+			t.Errorf("%q: not found by gen.FileByName", test.path)
+			continue
+		}
+		if f.Generate != test.wantGenerate {
+			t.Errorf("%q: Generate=%v, want %v", test.path, f.Generate, test.wantGenerate)
+		}
+	}
+}
+
+// makeRequest returns a CodeGeneratorRequest for the given protoc inputs.
+//
+// It does this by running protoc with the current binary as the protoc-gen-go
+// plugin. This "plugin" produces a single file, named 'request', which contains
+// the code generator request.
+func makeRequest(t *testing.T, args ...string) *pluginpb.CodeGeneratorRequest {
+	workdir, err := ioutil.TempDir("", "test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(workdir)
+
+	cmd := exec.Command("protoc", "--plugin=protoc-gen-go="+os.Args[0])
+	cmd.Args = append(cmd.Args, "--go_out="+workdir, "-Itestdata")
+	cmd.Args = append(cmd.Args, args...)
+	cmd.Env = append(os.Environ(), "RUN_AS_PROTOC_PLUGIN=1")
+	out, err := cmd.CombinedOutput()
+	if len(out) > 0 || err != nil {
+		t.Log("RUNNING: ", strings.Join(cmd.Args, " "))
+	}
+	if len(out) > 0 {
+		t.Log(string(out))
+	}
+	if err != nil {
+		t.Fatalf("protoc: %v", err)
+	}
+
+	b, err := ioutil.ReadFile(filepath.Join(workdir, "request"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	req := &pluginpb.CodeGeneratorRequest{}
+	if err := proto.UnmarshalText(string(b), req); err != nil {
+		t.Fatal(err)
+	}
+	return req
+}
+
+func init() {
+	if os.Getenv("RUN_AS_PROTOC_PLUGIN") != "" {
+		Run(func(p *Plugin) error {
+			g := p.NewGeneratedFile("request")
+			return proto.MarshalText(g, p.Request)
+		})
+		os.Exit(0)
+	}
+}