Add extensions to the generator.
R=r
CC=golang-dev
http://codereview.appspot.com/774041
diff --git a/compiler/testdata/Makefile b/compiler/testdata/Makefile
index 0cc9ad1..3eb2efb 100644
--- a/compiler/testdata/Makefile
+++ b/compiler/testdata/Makefile
@@ -37,9 +37,10 @@
include $(GOROOT)/src/Make.common
include $(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/Make.protobuf
-CLEANFILES+=*.pb.go
+CLEANFILES+=*.pb.go extension_test
-test: golden testbuild
+test: golden testbuild extension_test
+ ./extension_test
@echo PASS
golden:
@@ -51,6 +52,9 @@
testbuild: main.$O
$(LD) -L. main.$O
+extension_test: extension_test.$O
+ $(LD) -L. -o $@ $<
+
multi.a: multi3.pb.$O multi2.pb.$O multi1.pb.$O
rm -f multi.a
$(QUOTED_GOBIN)/gopack grc $@ $<
@@ -61,3 +65,4 @@
test.pb.go: imp.pb.go
multi1.pb.go: multi2.pb.go multi3.pb.go
main.$O: imp.pb.$O test.pb.$O multi.a
+extension_test.$O: extension_base.pb.$O extension_user.pb.$O
diff --git a/compiler/testdata/extension_base.proto b/compiler/testdata/extension_base.proto
new file mode 100644
index 0000000..5f91628
--- /dev/null
+++ b/compiler/testdata/extension_base.proto
@@ -0,0 +1,38 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc. All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package extension_base;
+
+message BaseMessage {
+ optional int32 height = 1;
+ extensions 4 to 9;
+ extensions 16 to max;
+}
diff --git a/compiler/testdata/extension_test.go b/compiler/testdata/extension_test.go
new file mode 100644
index 0000000..1ddb229
--- /dev/null
+++ b/compiler/testdata/extension_test.go
@@ -0,0 +1,159 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc. All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test that we can use protocol buffers that use extensions.
+
+package main
+
+import (
+ "testing"
+
+ "goprotobuf.googlecode.com/hg/proto"
+ base "extension_base.pb"
+ user "extension_user.pb"
+)
+
+func TestSingleFieldExtension(t *testing.T) {
+ bm := base.NewBaseMessage()
+ bm.Height = proto.Int32(178)
+
+ // Use extension within scope of another type.
+ vol := proto.Uint32(11)
+ t.Logf("bm: %T, user.LoudMessage_Volume: %T", bm, user.LoudMessage_Volume)
+ err := proto.SetExtension(bm, user.LoudMessage_Volume, vol)
+ if err != nil {
+ t.Fatal("Failed setting extension:", err)
+ }
+ buf, err := proto.Marshal(bm)
+ if err != nil {
+ t.Fatal("Failed encoding message with extension:", err)
+ }
+ bm_new := base.NewBaseMessage()
+ if err := proto.Unmarshal(buf, bm_new); err != nil {
+ t.Fatal("Failed decoding message with extension:", err)
+ }
+ if !proto.HasExtension(bm_new, user.LoudMessage_Volume) {
+ t.Fatal("Decoded message didn't contain extension.")
+ }
+ vol_out, err := proto.GetExtension(bm_new, user.LoudMessage_Volume)
+ if err != nil {
+ t.Fatal("Failed getting extension:", err)
+ }
+ if v := vol_out.(*uint32); *v != *vol {
+ t.Errorf("vol_out = %v, expected %v", *v, *vol)
+ }
+ proto.ClearExtension(bm_new, user.LoudMessage_Volume)
+ if proto.HasExtension(bm_new, user.LoudMessage_Volume) {
+ t.Fatal("Failed clearing extension.")
+ }
+}
+
+func TestMessageExtension(t *testing.T) {
+ bm := base.NewBaseMessage()
+ bm.Height = proto.Int32(179)
+
+ // Use extension that is itself a message.
+ um := &user.UserMessage{
+ Name: proto.String("Dave"),
+ Rank: proto.String("Major"),
+ }
+ err := proto.SetExtension(bm, user.LoginMessage_UserMessage, um)
+ if err != nil {
+ t.Fatal("Failed setting extension:", err)
+ }
+ buf, err := proto.Marshal(bm)
+ if err != nil {
+ t.Fatal("Failed encoding message with extension:", err)
+ }
+ bm_new := base.NewBaseMessage()
+ if err := proto.Unmarshal(buf, bm_new); err != nil {
+ t.Fatal("Failed decoding message with extension:", err)
+ }
+ if !proto.HasExtension(bm_new, user.LoginMessage_UserMessage) {
+ t.Fatal("Decoded message didn't contain extension.")
+ }
+ um_out, err := proto.GetExtension(bm_new, user.LoginMessage_UserMessage)
+ if err != nil {
+ t.Fatal("Failed getting extension:", err)
+ }
+ if n := um_out.(*user.UserMessage).Name; *n != *um.Name {
+ t.Errorf("um_out.Name = %q, expected %q", *n, *um.Name)
+ }
+ if r := um_out.(*user.UserMessage).Rank; *r != *um.Rank {
+ t.Errorf("um_out.Rank = %q, expected %q", *r, *um.Rank)
+ }
+ proto.ClearExtension(bm_new, user.LoginMessage_UserMessage)
+ if proto.HasExtension(bm_new, user.LoginMessage_UserMessage) {
+ t.Fatal("Failed clearing extension.")
+ }
+}
+
+func TestTopLevelExtension(t *testing.T) {
+ bm := base.NewBaseMessage()
+ bm.Height = proto.Int32(179)
+
+ width := proto.Int32(17)
+ err := proto.SetExtension(bm, user.E_Width, width)
+ if err != nil {
+ t.Fatal("Failed setting extension:", err)
+ }
+ buf, err := proto.Marshal(bm)
+ if err != nil {
+ t.Fatal("Failed encoding message with extension:", err)
+ }
+ bm_new := base.NewBaseMessage()
+ if err := proto.Unmarshal(buf, bm_new); err != nil {
+ t.Fatal("Failed decoding message with extension:", err)
+ }
+ if !proto.HasExtension(bm_new, user.E_Width) {
+ t.Fatal("Decoded message didn't contain extension.")
+ }
+ width_out, err := proto.GetExtension(bm_new, user.E_Width)
+ if err != nil {
+ t.Fatal("Failed getting extension:", err)
+ }
+ if w := width_out.(*int32); *w != *width {
+ t.Errorf("width_out = %v, expected %v", *w, *width)
+ }
+ proto.ClearExtension(bm_new, user.E_Width)
+ if proto.HasExtension(bm_new, user.E_Width) {
+ t.Fatal("Failed clearing extension.")
+ }
+}
+
+func main() {
+ // simpler than rigging up gotest
+ testing.Main([]testing.Test{
+ testing.Test{"TestSingleFieldExtension", TestSingleFieldExtension},
+ testing.Test{"TestMessageExtension", TestMessageExtension},
+ testing.Test{"TestTopLevelExtension", TestTopLevelExtension},
+ })
+}
diff --git a/compiler/testdata/extension_user.proto b/compiler/testdata/extension_user.proto
new file mode 100644
index 0000000..6fb3d72
--- /dev/null
+++ b/compiler/testdata/extension_user.proto
@@ -0,0 +1,73 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc. All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import "extension_base.proto";
+
+package extension_user;
+
+message UserMessage {
+ optional string name = 1;
+ optional string rank = 2;
+}
+
+// Extend with a message
+extend extension_base.BaseMessage {
+ optional UserMessage user_message = 5;
+}
+
+// Extend with some primitive types
+extend extension_base.BaseMessage {
+ optional int32 width = 6;
+ optional int64 area = 7;
+}
+
+// Extend inside the scope of another type
+message LoudMessage {
+ extend extension_base.BaseMessage {
+ optional uint32 volume = 8;
+ }
+ extensions 100 to max;
+}
+
+// Extend inside the scope of another type, using a message.
+message LoginMessage {
+ extend extension_base.BaseMessage {
+ required UserMessage user_message = 16;
+ }
+}
+
+// An extension of an extension
+message Announcement {
+ optional string words = 1;
+ extend LoudMessage {
+ optional Announcement loud_ext = 100;
+ }
+}
diff --git a/compiler/testdata/test.pb.go.golden b/compiler/testdata/test.pb.go.golden
index 0d7a7cb..6807d20 100644
--- a/compiler/testdata/test.pb.go.golden
+++ b/compiler/testdata/test.pb.go.golden
@@ -84,6 +84,7 @@
type Reply struct {
Found []*Reply_Entry "PB(bytes,1,rep,name=found)"
+ XXX_extensions map[int32][]byte
XXX_unrecognized []byte
}
func (this *Reply) Reset() {
@@ -93,6 +94,19 @@
return new(Reply)
}
+var extRange_Reply = []proto.ExtensionRange{
+ proto.ExtensionRange{100, 536870911},
+}
+func (*Reply) ExtensionRangeArray() []proto.ExtensionRange {
+ return extRange_Reply
+}
+func (this *Reply) ExtensionMap() map[int32][]byte {
+ if this.XXX_extensions == nil {
+ this.XXX_extensions = make(map[int32][]byte)
+ }
+ return this.XXX_extensions
+}
+
type Reply_Entry struct {
KeyThatNeeds_1234camel_CasIng *int64 "PB(varint,1,req,name=key_that_needs_1234camel_CasIng)"
Value *int64 "PB(varint,2,opt,name=value,def=7)"
@@ -117,6 +131,20 @@
return new(ReplyExtensions)
}
+var ReplyExtensions_Time = &proto.ExtensionDesc{
+ ExtendedType: (*Reply)(nil),
+ ExtensionType: (*float64)(nil),
+ Field: 101,
+ Tag: "PB(fixed64,101,opt,name=time)",
+}
+
+var E_Tag = &proto.ExtensionDesc{
+ ExtendedType: (*Reply)(nil),
+ ExtensionType: (*string)(nil),
+ Field: 103,
+ Tag: "PB(bytes,103,opt,name=tag)",
+}
+
func init() {
proto.RegisterEnum("my_test.HatType", HatType_name, HatType_value)
proto.RegisterEnum("my_test.Days", Days_name, Days_value)
diff --git a/compiler/testdata/test.proto b/compiler/testdata/test.proto
index f7e7a3d..ef91b03 100644
--- a/compiler/testdata/test.proto
+++ b/compiler/testdata/test.proto
@@ -73,3 +73,8 @@
optional double time = 101;
}
}
+
+// top-level extension
+extend Reply {
+ optional string tag = 103;
+}