xref: /aosp_15_r20/external/golang-protobuf/reflect/protoreflect/value_test.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package protoreflect
6
7import (
8	"bytes"
9	"math"
10	"reflect"
11	"testing"
12)
13
14var (
15	fakeMessage = new(struct{ Message })
16	fakeList    = new(struct{ List })
17	fakeMap     = new(struct{ Map })
18)
19
20func TestValue(t *testing.T) {
21
22	tests := []struct {
23		in   Value
24		want interface{}
25	}{
26		{in: Value{}},
27		{in: ValueOf(nil)},
28		{in: ValueOf(true), want: true},
29		{in: ValueOf(int32(math.MaxInt32)), want: int32(math.MaxInt32)},
30		{in: ValueOf(int64(math.MaxInt64)), want: int64(math.MaxInt64)},
31		{in: ValueOf(uint32(math.MaxUint32)), want: uint32(math.MaxUint32)},
32		{in: ValueOf(uint64(math.MaxUint64)), want: uint64(math.MaxUint64)},
33		{in: ValueOf(float32(math.MaxFloat32)), want: float32(math.MaxFloat32)},
34		{in: ValueOf(float64(math.MaxFloat64)), want: float64(math.MaxFloat64)},
35		{in: ValueOf(string("hello")), want: string("hello")},
36		{in: ValueOf([]byte("hello")), want: []byte("hello")},
37		{in: ValueOf(fakeMessage), want: fakeMessage},
38		{in: ValueOf(fakeList), want: fakeList},
39		{in: ValueOf(fakeMap), want: fakeMap},
40	}
41
42	for _, tt := range tests {
43		got := tt.in.Interface()
44		if !reflect.DeepEqual(got, tt.want) {
45			t.Errorf("Value(%v).Interface() = %v, want %v", tt.in, got, tt.want)
46		}
47
48		if got := tt.in.IsValid(); got != (tt.want != nil) {
49			t.Errorf("Value(%v).IsValid() = %v, want %v", tt.in, got, tt.want != nil)
50		}
51		switch want := tt.want.(type) {
52		case int32:
53			if got := tt.in.Int(); got != int64(want) {
54				t.Errorf("Value(%v).Int() = %v, want %v", tt.in, got, tt.want)
55			}
56		case int64:
57			if got := tt.in.Int(); got != int64(want) {
58				t.Errorf("Value(%v).Int() = %v, want %v", tt.in, got, tt.want)
59			}
60		case uint32:
61			if got := tt.in.Uint(); got != uint64(want) {
62				t.Errorf("Value(%v).Uint() = %v, want %v", tt.in, got, tt.want)
63			}
64		case uint64:
65			if got := tt.in.Uint(); got != uint64(want) {
66				t.Errorf("Value(%v).Uint() = %v, want %v", tt.in, got, tt.want)
67			}
68		case float32:
69			if got := tt.in.Float(); got != float64(want) {
70				t.Errorf("Value(%v).Float() = %v, want %v", tt.in, got, tt.want)
71			}
72		case float64:
73			if got := tt.in.Float(); got != float64(want) {
74				t.Errorf("Value(%v).Float() = %v, want %v", tt.in, got, tt.want)
75			}
76		case string:
77			if got := tt.in.String(); got != string(want) {
78				t.Errorf("Value(%v).String() = %v, want %v", tt.in, got, tt.want)
79			}
80		case []byte:
81			if got := tt.in.Bytes(); !bytes.Equal(got, want) {
82				t.Errorf("Value(%v).Bytes() = %v, want %v", tt.in, got, tt.want)
83			}
84		case EnumNumber:
85			if got := tt.in.Enum(); got != want {
86				t.Errorf("Value(%v).Enum() = %v, want %v", tt.in, got, tt.want)
87			}
88		case Message:
89			if got := tt.in.Message(); got != want {
90				t.Errorf("Value(%v).Message() = %v, want %v", tt.in, got, tt.want)
91			}
92		case List:
93			if got := tt.in.List(); got != want {
94				t.Errorf("Value(%v).List() = %v, want %v", tt.in, got, tt.want)
95			}
96		case Map:
97			if got := tt.in.Map(); got != want {
98				t.Errorf("Value(%v).Map() = %v, want %v", tt.in, got, tt.want)
99			}
100		}
101	}
102}
103
104func TestValueEqual(t *testing.T) {
105	tests := []struct {
106		x, y Value
107		want bool
108	}{
109		{Value{}, Value{}, true},
110		{Value{}, ValueOfBool(true), false},
111		{ValueOfBool(true), ValueOfBool(true), true},
112		{ValueOfBool(true), ValueOfBool(false), false},
113		{ValueOfBool(false), ValueOfInt32(0), false},
114		{ValueOfInt32(0), ValueOfInt32(0), true},
115		{ValueOfInt32(0), ValueOfInt32(1), false},
116		{ValueOfInt32(0), ValueOfInt64(0), false},
117		{ValueOfInt64(123), ValueOfInt64(123), true},
118		{ValueOfFloat64(0), ValueOfFloat64(0), true},
119		{ValueOfFloat64(math.NaN()), ValueOfFloat64(math.NaN()), true},
120		{ValueOfFloat64(math.NaN()), ValueOfFloat64(0), false},
121		{ValueOfFloat64(math.Inf(1)), ValueOfFloat64(math.Inf(1)), true},
122		{ValueOfFloat64(math.Inf(-1)), ValueOfFloat64(math.Inf(1)), false},
123		{ValueOfBytes(nil), ValueOfBytes(nil), true},
124		{ValueOfBytes(nil), ValueOfBytes([]byte{}), true},
125		{ValueOfBytes(nil), ValueOfBytes([]byte{1}), false},
126		{ValueOfEnum(0), ValueOfEnum(0), true},
127		{ValueOfEnum(0), ValueOfEnum(1), false},
128		{ValueOfBool(false), ValueOfMessage(fakeMessage), false},
129		{ValueOfMessage(fakeMessage), ValueOfList(fakeList), false},
130		{ValueOfList(fakeList), ValueOfMap(fakeMap), false},
131		{ValueOfMap(fakeMap), ValueOfMessage(fakeMessage), false},
132
133		// Composite types are not tested here.
134		// See proto.TestEqual.
135	}
136
137	for _, tt := range tests {
138		got := tt.x.Equal(tt.y)
139		if got != tt.want {
140			t.Errorf("(%v).Equal(%v) = %v, want %v", tt.x, tt.y, got, tt.want)
141		}
142	}
143}
144
145func BenchmarkValue(b *testing.B) {
146	const testdata = "The quick brown fox jumped over the lazy dog."
147	var sink1 string
148	var sink2 Value
149	var sink3 interface{}
150
151	// Baseline measures the time to store a string into a native variable.
152	b.Run("Baseline", func(b *testing.B) {
153		b.ReportAllocs()
154		for i := 0; i < b.N; i++ {
155			sink1 = testdata[:len(testdata)%(i+1)]
156		}
157	})
158
159	// Inline measures the time to store a string into a Value,
160	// assuming that the compiler could inline the ValueOf function call.
161	b.Run("Inline", func(b *testing.B) {
162		b.ReportAllocs()
163		for i := 0; i < b.N; i++ {
164			sink2 = valueOfString(testdata[:len(testdata)%(i+1)])
165		}
166	})
167
168	// Value measures the time to store a string into a Value using the general
169	// ValueOf function call. This should be identical to Inline.
170	//
171	// NOTE: As of Go1.11, this is not as efficient as Inline due to the lack
172	// of some compiler optimizations:
173	//	https://golang.org/issue/22310
174	//	https://golang.org/issue/25189
175	b.Run("Value", func(b *testing.B) {
176		b.ReportAllocs()
177		for i := 0; i < b.N; i++ {
178			sink2 = ValueOf(string(testdata[:len(testdata)%(i+1)]))
179		}
180	})
181
182	// Interface measures the time to store a string into an interface.
183	b.Run("Interface", func(b *testing.B) {
184		b.ReportAllocs()
185		for i := 0; i < b.N; i++ {
186			sink3 = string(testdata[:len(testdata)%(i+1)])
187		}
188	})
189
190	_, _, _ = sink1, sink2, sink3
191}
192