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/golang/protobuf/proto"
42	base "github.com/golang/protobuf/protoc-gen-go/testdata/extension_base"
43	user "github.com/golang/protobuf/protoc-gen-go/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	err := proto.SetExtension(bm, user.E_LoudMessage_Volume, vol)
54	if err != nil {
55		t.Fatal("Failed setting extension:", err)
56	}
57	buf, err := proto.Marshal(bm)
58	if err != nil {
59		t.Fatal("Failed encoding message with extension:", err)
60	}
61	bm_new := new(base.BaseMessage)
62	if err := proto.Unmarshal(buf, bm_new); err != nil {
63		t.Fatal("Failed decoding message with extension:", err)
64	}
65	if !proto.HasExtension(bm_new, user.E_LoudMessage_Volume) {
66		t.Fatal("Decoded message didn't contain extension.")
67	}
68	vol_out, err := proto.GetExtension(bm_new, user.E_LoudMessage_Volume)
69	if err != nil {
70		t.Fatal("Failed getting extension:", err)
71	}
72	if v := vol_out.(*uint32); *v != *vol {
73		t.Errorf("vol_out = %v, expected %v", *v, *vol)
74	}
75	proto.ClearExtension(bm_new, user.E_LoudMessage_Volume)
76	if proto.HasExtension(bm_new, user.E_LoudMessage_Volume) {
77		t.Fatal("Failed clearing extension.")
78	}
79}
80
81func TestMessageExtension(t *testing.T) {
82	bm := &base.BaseMessage{
83		Height: proto.Int32(179),
84	}
85
86	// Use extension that is itself a message.
87	um := &user.UserMessage{
88		Name: proto.String("Dave"),
89		Rank: proto.String("Major"),
90	}
91	err := proto.SetExtension(bm, user.E_LoginMessage_UserMessage, um)
92	if err != nil {
93		t.Fatal("Failed setting extension:", err)
94	}
95	buf, err := proto.Marshal(bm)
96	if err != nil {
97		t.Fatal("Failed encoding message with extension:", err)
98	}
99	bm_new := new(base.BaseMessage)
100	if err := proto.Unmarshal(buf, bm_new); err != nil {
101		t.Fatal("Failed decoding message with extension:", err)
102	}
103	if !proto.HasExtension(bm_new, user.E_LoginMessage_UserMessage) {
104		t.Fatal("Decoded message didn't contain extension.")
105	}
106	um_out, err := proto.GetExtension(bm_new, user.E_LoginMessage_UserMessage)
107	if err != nil {
108		t.Fatal("Failed getting extension:", err)
109	}
110	if n := um_out.(*user.UserMessage).Name; *n != *um.Name {
111		t.Errorf("um_out.Name = %q, expected %q", *n, *um.Name)
112	}
113	if r := um_out.(*user.UserMessage).Rank; *r != *um.Rank {
114		t.Errorf("um_out.Rank = %q, expected %q", *r, *um.Rank)
115	}
116	proto.ClearExtension(bm_new, user.E_LoginMessage_UserMessage)
117	if proto.HasExtension(bm_new, user.E_LoginMessage_UserMessage) {
118		t.Fatal("Failed clearing extension.")
119	}
120}
121
122func TestTopLevelExtension(t *testing.T) {
123	bm := &base.BaseMessage{
124		Height: proto.Int32(179),
125	}
126
127	width := proto.Int32(17)
128	err := proto.SetExtension(bm, user.E_Width, width)
129	if err != nil {
130		t.Fatal("Failed setting extension:", err)
131	}
132	buf, err := proto.Marshal(bm)
133	if err != nil {
134		t.Fatal("Failed encoding message with extension:", err)
135	}
136	bm_new := new(base.BaseMessage)
137	if err := proto.Unmarshal(buf, bm_new); err != nil {
138		t.Fatal("Failed decoding message with extension:", err)
139	}
140	if !proto.HasExtension(bm_new, user.E_Width) {
141		t.Fatal("Decoded message didn't contain extension.")
142	}
143	width_out, err := proto.GetExtension(bm_new, user.E_Width)
144	if err != nil {
145		t.Fatal("Failed getting extension:", err)
146	}
147	if w := width_out.(*int32); *w != *width {
148		t.Errorf("width_out = %v, expected %v", *w, *width)
149	}
150	proto.ClearExtension(bm_new, user.E_Width)
151	if proto.HasExtension(bm_new, user.E_Width) {
152		t.Fatal("Failed clearing extension.")
153	}
154}
155
156func TestMessageSetWireFormat(t *testing.T) {
157	osm := new(base.OldStyleMessage)
158	osp := &user.OldStyleParcel{
159		Name:   proto.String("Dave"),
160		Height: proto.Int32(178),
161	}
162
163	err := proto.SetExtension(osm, user.E_OldStyleParcel_MessageSetExtension, osp)
164	if err != nil {
165		t.Fatal("Failed setting extension:", err)
166	}
167
168	buf, err := proto.Marshal(osm)
169	if err != nil {
170		t.Fatal("Failed encoding message:", err)
171	}
172
173	// Data generated from Python implementation.
174	expected := []byte{
175		11, 16, 209, 15, 26, 9, 10, 4, 68, 97, 118, 101, 16, 178, 1, 12,
176	}
177
178	if !bytes.Equal(expected, buf) {
179		t.Errorf("Encoding mismatch.\nwant %+v\n got %+v", expected, buf)
180	}
181
182	// Check that it is restored correctly.
183	osm = new(base.OldStyleMessage)
184	if err := proto.Unmarshal(buf, osm); err != nil {
185		t.Fatal("Failed decoding message:", err)
186	}
187	osp_out, err := proto.GetExtension(osm, user.E_OldStyleParcel_MessageSetExtension)
188	if err != nil {
189		t.Fatal("Failed getting extension:", err)
190	}
191	osp = osp_out.(*user.OldStyleParcel)
192	if *osp.Name != "Dave" || *osp.Height != 178 {
193		t.Errorf("Retrieved extension from decoded message is not correct: %+v", osp)
194	}
195}
196
197func main() {
198	// simpler than rigging up gotest
199	testing.Main(regexp.MatchString, []testing.InternalTest{
200		{"TestSingleFieldExtension", TestSingleFieldExtension},
201		{"TestMessageExtension", TestMessageExtension},
202		{"TestTopLevelExtension", TestTopLevelExtension},
203	},
204		[]testing.InternalBenchmark{},
205		[]testing.InternalExample{})
206}
207