1// Protocol Buffers for Go with Gadgets
2//
3// Copyright (c) 2013, The GoGo Authors. All rights reserved.
4// http://github.com/gogo/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//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29package test
30
31import (
32	"github.com/gogo/protobuf/proto"
33	"math"
34	math_rand "math/rand"
35	"testing"
36	"time"
37)
38
39//func SetRawExtension(base extendableProto, id int32, b []byte) {
40//func HasExtension(pb extendableProto, extension *ExtensionDesc) bool {
41//func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
42//func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
43//func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
44//func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{}) error {
45
46type extendable interface {
47	proto.Message
48	ExtensionRangeArray() []proto.ExtensionRange
49}
50
51func check(t *testing.T, m extendable, fieldA float64, ext *proto.ExtensionDesc) {
52	if !proto.HasExtension(m, ext) {
53		t.Fatalf("expected extension to be set")
54	}
55	fieldA2Interface, err := proto.GetExtension(m, ext)
56	if err != nil {
57		panic(err)
58	}
59	fieldA2 := fieldA2Interface.(*float64)
60	if fieldA != *fieldA2 {
61		t.Fatalf("Expected %f got %f", fieldA, *fieldA2)
62	}
63	fieldA3Interface, err := proto.GetUnsafeExtension(m, ext.Field)
64	if err != nil {
65		panic(err)
66	}
67	fieldA3 := fieldA3Interface.(*float64)
68	if fieldA != *fieldA3 {
69		t.Fatalf("Expected %f got %f", fieldA, *fieldA3)
70	}
71	proto.ClearExtension(m, ext)
72	if proto.HasExtension(m, ext) {
73		t.Fatalf("expected extension to be cleared")
74	}
75}
76
77var fieldA float64
78var fieldABytes []byte
79var extr = math_rand.New(math_rand.NewSource(time.Now().UnixNano()))
80
81func init() {
82	fieldA = float64(1.1)
83	fieldABits := math.Float64bits(fieldA)
84	x := uint64(uint32(100)<<3 | uint32(proto.WireFixed64))
85	fieldABytes = encodeVarintPopulateThetest(nil, x)
86	fieldABytes = append(fieldABytes, uint8(fieldABits))
87	fieldABytes = append(fieldABytes, uint8(fieldABits>>8))
88	fieldABytes = append(fieldABytes, uint8(fieldABits>>16))
89	fieldABytes = append(fieldABytes, uint8(fieldABits>>24))
90	fieldABytes = append(fieldABytes, uint8(fieldABits>>32))
91	fieldABytes = append(fieldABytes, uint8(fieldABits>>40))
92	fieldABytes = append(fieldABytes, uint8(fieldABits>>48))
93	fieldABytes = append(fieldABytes, uint8(fieldABits>>56))
94}
95
96func TestExtensionsMyExtendable(t *testing.T) {
97	m := NewPopulatedMyExtendable(extr, false)
98	err := proto.SetExtension(m, E_FieldA, &fieldA)
99	if err != nil {
100		panic(err)
101	}
102	check(t, m, fieldA, E_FieldA)
103	proto.SetRawExtension(m, 100, fieldABytes)
104	check(t, m, fieldA, E_FieldA)
105}
106
107func TestExtensionsNoExtensionsMapSetExtension(t *testing.T) {
108	m := NewPopulatedNoExtensionsMap(extr, false)
109	err := proto.SetExtension(m, E_FieldA1, &fieldA)
110	if err != nil {
111		panic(err)
112	}
113	check(t, m, fieldA, E_FieldA1)
114}
115
116func TestExtensionsNoExtensionsMapSetRawExtension(t *testing.T) {
117	m := NewPopulatedNoExtensionsMap(extr, false)
118	proto.SetRawExtension(m, 100, fieldABytes)
119	check(t, m, fieldA, E_FieldA1)
120}
121
122func TestUnsafeExtension(t *testing.T) {
123	m := NewPopulatedMyExtendable(extr, false)
124	err := proto.SetUnsafeExtension(m, E_FieldA.Field, &fieldA)
125	if err != nil {
126		panic(err)
127	}
128	check(t, m, fieldA, E_FieldA)
129}
130
131//See another version of this test in proto/extensions_test.go
132func TestGetExtensionStability(t *testing.T) {
133	check := func(m *NoExtensionsMap) bool {
134		ext1, err := proto.GetExtension(m, E_FieldB1)
135		if err != nil {
136			t.Fatalf("GetExtension() failed: %s", err)
137		}
138		ext2, err := proto.GetExtension(m, E_FieldB1)
139		if err != nil {
140			t.Fatalf("GetExtension() failed: %s", err)
141		}
142		return ext1.(*NinOptNative).Equal(ext2)
143	}
144	msg := &NoExtensionsMap{Field1: proto.Int64(2)}
145	ext0 := &NinOptNative{Field1: proto.Float64(1)}
146	if err := proto.SetExtension(msg, E_FieldB1, ext0); err != nil {
147		t.Fatalf("Could not set ext1: %s", ext0)
148	}
149	if !check(msg) {
150		t.Errorf("GetExtension() not stable before marshaling")
151	}
152	bb, err := proto.Marshal(msg)
153	if err != nil {
154		t.Fatalf("Marshal() failed: %s", err)
155	}
156	msg1 := &NoExtensionsMap{}
157	err = proto.Unmarshal(bb, msg1)
158	if err != nil {
159		t.Fatalf("Unmarshal() failed: %s", err)
160	}
161	if !check(msg1) {
162		t.Errorf("GetExtension() not stable after unmarshaling")
163	}
164}
165