1// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 The Go Authors.  All rights reserved.
4// https://github.com/golang/protobuf
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10//     * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12//     * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16//     * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32// Test that we can use protocol buffers that use extensions.
33
34package testdata
35
36import (
37	"bytes"
38	"regexp"
39	"testing"
40
41	"github.com/gogo/protobuf/proto"
42	base "github.com/gogo/protobuf/protoc-gen-gogo/testdata/extension_base"
43	user "github.com/gogo/protobuf/protoc-gen-gogo/testdata/extension_user"
44)
45
46func TestSingleFieldExtension(t *testing.T) {
47	bm := &base.BaseMessage{
48		Height: proto.Int32(178),
49	}
50
51	// Use extension within scope of another type.
52	vol := proto.Uint32(11)
53	if err := proto.SetExtension(bm, user.E_LoudMessage_Volume, vol); err != nil {
54		t.Fatal("Failed setting extension:", err)
55	}
56	buf, berr := proto.Marshal(bm)
57	if berr != nil {
58		t.Fatal("Failed encoding message with extension:", berr)
59	}
60	bm_new := new(base.BaseMessage)
61	if err := proto.Unmarshal(buf, bm_new); err != nil {
62		t.Fatal("Failed decoding message with extension:", err)
63	}
64	if !proto.HasExtension(bm_new, user.E_LoudMessage_Volume) {
65		t.Fatal("Decoded message didn't contain extension.")
66	}
67	vol_out, err := proto.GetExtension(bm_new, user.E_LoudMessage_Volume)
68	if err != nil {
69		t.Fatal("Failed getting extension:", err)
70	}
71	if v := vol_out.(*uint32); *v != *vol {
72		t.Errorf("vol_out = %v, expected %v", *v, *vol)
73	}
74	proto.ClearExtension(bm_new, user.E_LoudMessage_Volume)
75	if proto.HasExtension(bm_new, user.E_LoudMessage_Volume) {
76		t.Fatal("Failed clearing extension.")
77	}
78}
79
80func TestMessageExtension(t *testing.T) {
81	bm := &base.BaseMessage{
82		Height: proto.Int32(179),
83	}
84
85	// Use extension that is itself a message.
86	um := &user.UserMessage{
87		Name: proto.String("Dave"),
88		Rank: proto.String("Major"),
89	}
90	if err := proto.SetExtension(bm, user.E_LoginMessage_UserMessage, um); err != nil {
91		t.Fatal("Failed setting extension:", err)
92	}
93	buf, berr := proto.Marshal(bm)
94	if berr != nil {
95		t.Fatal("Failed encoding message with extension:", berr)
96	}
97	bm_new := new(base.BaseMessage)
98	if err := proto.Unmarshal(buf, bm_new); err != nil {
99		t.Fatal("Failed decoding message with extension:", err)
100	}
101	if !proto.HasExtension(bm_new, user.E_LoginMessage_UserMessage) {
102		t.Fatal("Decoded message didn't contain extension.")
103	}
104	um_out, err := proto.GetExtension(bm_new, user.E_LoginMessage_UserMessage)
105	if err != nil {
106		t.Fatal("Failed getting extension:", err)
107	}
108	if n := um_out.(*user.UserMessage).Name; *n != *um.Name {
109		t.Errorf("um_out.Name = %q, expected %q", *n, *um.Name)
110	}
111	if r := um_out.(*user.UserMessage).Rank; *r != *um.Rank {
112		t.Errorf("um_out.Rank = %q, expected %q", *r, *um.Rank)
113	}
114	proto.ClearExtension(bm_new, user.E_LoginMessage_UserMessage)
115	if proto.HasExtension(bm_new, user.E_LoginMessage_UserMessage) {
116		t.Fatal("Failed clearing extension.")
117	}
118}
119
120func TestTopLevelExtension(t *testing.T) {
121	bm := &base.BaseMessage{
122		Height: proto.Int32(179),
123	}
124
125	width := proto.Int32(17)
126	if err := proto.SetExtension(bm, user.E_Width, width); err != nil {
127		t.Fatal("Failed setting extension:", err)
128	}
129	buf, berr := proto.Marshal(bm)
130	if berr != nil {
131		t.Fatal("Failed encoding message with extension:", berr)
132	}
133	bm_new := new(base.BaseMessage)
134	if err := proto.Unmarshal(buf, bm_new); err != nil {
135		t.Fatal("Failed decoding message with extension:", err)
136	}
137	if !proto.HasExtension(bm_new, user.E_Width) {
138		t.Fatal("Decoded message didn't contain extension.")
139	}
140	width_out, err := proto.GetExtension(bm_new, user.E_Width)
141	if err != nil {
142		t.Fatal("Failed getting extension:", err)
143	}
144	if w := width_out.(*int32); *w != *width {
145		t.Errorf("width_out = %v, expected %v", *w, *width)
146	}
147	proto.ClearExtension(bm_new, user.E_Width)
148	if proto.HasExtension(bm_new, user.E_Width) {
149		t.Fatal("Failed clearing extension.")
150	}
151}
152
153func TestMessageSetWireFormat(t *testing.T) {
154	osm := new(base.OldStyleMessage)
155	osp := &user.OldStyleParcel{
156		Name:   proto.String("Dave"),
157		Height: proto.Int32(178),
158	}
159
160	if err := proto.SetExtension(osm, user.E_OldStyleParcel_MessageSetExtension, osp); err != nil {
161		t.Fatal("Failed setting extension:", err)
162	}
163
164	buf, berr := proto.Marshal(osm)
165	if berr != nil {
166		t.Fatal("Failed encoding message:", berr)
167	}
168
169	// Data generated from Python implementation.
170	expected := []byte{
171		11, 16, 209, 15, 26, 9, 10, 4, 68, 97, 118, 101, 16, 178, 1, 12,
172	}
173
174	if !bytes.Equal(expected, buf) {
175		t.Errorf("Encoding mismatch.\nwant %+v\n got %+v", expected, buf)
176	}
177
178	// Check that it is restored correctly.
179	osm = new(base.OldStyleMessage)
180	if err := proto.Unmarshal(buf, osm); err != nil {
181		t.Fatal("Failed decoding message:", err)
182	}
183	osp_out, err := proto.GetExtension(osm, user.E_OldStyleParcel_MessageSetExtension)
184	if err != nil {
185		t.Fatal("Failed getting extension:", err)
186	}
187	osp = osp_out.(*user.OldStyleParcel)
188	if *osp.Name != "Dave" || *osp.Height != 178 {
189		t.Errorf("Retrieved extension from decoded message is not correct: %+v", osp)
190	}
191}
192
193func main() {
194	// simpler than rigging up gotest
195	testing.Main(regexp.MatchString, []testing.InternalTest{
196		{"TestSingleFieldExtension", TestSingleFieldExtension},
197		{"TestMessageExtension", TestMessageExtension},
198		{"TestTopLevelExtension", TestTopLevelExtension},
199	},
200		[]testing.InternalBenchmark{},
201		[]testing.InternalExample{})
202}
203