blob: c6bbb5841cd28ff2b5742beae7141b995969fb79 [file] [log] [blame]
Joe Tsaidbc9a122018-08-03 17:13:23 -07001// 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
14func TestValue(t *testing.T) {
15 fakeMessage := new(struct{ Message })
Joe Tsai4b7aff62018-11-14 14:05:19 -080016 fakeList := new(struct{ List })
Joe Tsaidbc9a122018-08-03 17:13:23 -070017 fakeMap := new(struct{ Map })
18
19 tests := []struct {
20 in Value
21 want interface{}
22 }{
Joe Tsaidbc9a122018-08-03 17:13:23 -070023 {in: Value{}},
24 {in: ValueOf(nil)},
25 {in: ValueOf(true), want: true},
26 {in: ValueOf(int32(math.MaxInt32)), want: int32(math.MaxInt32)},
27 {in: ValueOf(int64(math.MaxInt64)), want: int64(math.MaxInt64)},
28 {in: ValueOf(uint32(math.MaxUint32)), want: uint32(math.MaxUint32)},
29 {in: ValueOf(uint64(math.MaxUint64)), want: uint64(math.MaxUint64)},
30 {in: ValueOf(float32(math.MaxFloat32)), want: float32(math.MaxFloat32)},
31 {in: ValueOf(float64(math.MaxFloat64)), want: float64(math.MaxFloat64)},
32 {in: ValueOf(string("hello")), want: string("hello")},
33 {in: ValueOf([]byte("hello")), want: []byte("hello")},
34 {in: ValueOf(fakeMessage), want: fakeMessage},
Joe Tsai4b7aff62018-11-14 14:05:19 -080035 {in: ValueOf(fakeList), want: fakeList},
Joe Tsaidbc9a122018-08-03 17:13:23 -070036 {in: ValueOf(fakeMap), want: fakeMap},
37 }
38
39 for _, tt := range tests {
40 got := tt.in.Interface()
41 if !reflect.DeepEqual(got, tt.want) {
42 t.Errorf("Value(%v).Interface() = %v, want %v", tt.in, got, tt.want)
43 }
44
Joe Tsai812d9132018-09-12 11:26:15 -070045 if got := tt.in.IsValid(); got != (tt.want != nil) {
46 t.Errorf("Value(%v).IsValid() = %v, want %v", tt.in, got, tt.want != nil)
Joe Tsaidbc9a122018-08-03 17:13:23 -070047 }
48 switch want := tt.want.(type) {
49 case int32:
50 if got := tt.in.Int(); got != int64(want) {
51 t.Errorf("Value(%v).Int() = %v, want %v", tt.in, got, tt.want)
52 }
53 case int64:
54 if got := tt.in.Int(); got != int64(want) {
55 t.Errorf("Value(%v).Int() = %v, want %v", tt.in, got, tt.want)
56 }
57 case uint32:
58 if got := tt.in.Uint(); got != uint64(want) {
59 t.Errorf("Value(%v).Uint() = %v, want %v", tt.in, got, tt.want)
60 }
61 case uint64:
62 if got := tt.in.Uint(); got != uint64(want) {
63 t.Errorf("Value(%v).Uint() = %v, want %v", tt.in, got, tt.want)
64 }
65 case float32:
66 if got := tt.in.Float(); got != float64(want) {
67 t.Errorf("Value(%v).Float() = %v, want %v", tt.in, got, tt.want)
68 }
69 case float64:
70 if got := tt.in.Float(); got != float64(want) {
71 t.Errorf("Value(%v).Float() = %v, want %v", tt.in, got, tt.want)
72 }
73 case string:
74 if got := tt.in.String(); got != string(want) {
75 t.Errorf("Value(%v).String() = %v, want %v", tt.in, got, tt.want)
76 }
77 case []byte:
78 if got := tt.in.Bytes(); !bytes.Equal(got, want) {
79 t.Errorf("Value(%v).Bytes() = %v, want %v", tt.in, got, tt.want)
80 }
81 case EnumNumber:
82 if got := tt.in.Enum(); got != want {
83 t.Errorf("Value(%v).Enum() = %v, want %v", tt.in, got, tt.want)
84 }
85 case Message:
86 if got := tt.in.Message(); got != want {
87 t.Errorf("Value(%v).Message() = %v, want %v", tt.in, got, tt.want)
88 }
Joe Tsai4b7aff62018-11-14 14:05:19 -080089 case List:
90 if got := tt.in.List(); got != want {
91 t.Errorf("Value(%v).List() = %v, want %v", tt.in, got, tt.want)
92 }
Joe Tsaidbc9a122018-08-03 17:13:23 -070093 case Map:
94 if got := tt.in.Map(); got != want {
95 t.Errorf("Value(%v).Map() = %v, want %v", tt.in, got, tt.want)
96 }
Joe Tsaidbc9a122018-08-03 17:13:23 -070097 }
98 }
99}
100
101func BenchmarkValue(b *testing.B) {
102 const testdata = "The quick brown fox jumped over the lazy dog."
103 var sink1 string
104 var sink2 Value
105 var sink3 interface{}
106
107 // Baseline measures the time to store a string into a native variable.
108 b.Run("Baseline", func(b *testing.B) {
109 b.ReportAllocs()
110 for i := 0; i < b.N; i++ {
111 sink1 = testdata[:len(testdata)%(i+1)]
112 }
113 })
114
115 // Inline measures the time to store a string into a Value,
116 // assuming that the compiler could inline the ValueOf function call.
117 b.Run("Inline", func(b *testing.B) {
118 b.ReportAllocs()
119 for i := 0; i < b.N; i++ {
120 sink2 = valueOfString(testdata[:len(testdata)%(i+1)])
121 }
122 })
123
124 // Value measures the time to store a string into a Value using the general
125 // ValueOf function call. This should be identical to Inline.
126 //
127 // NOTE: As of Go1.11, this is not as efficient as Inline due to the lack
128 // of some compiler optimizations:
129 // https://golang.org/issue/22310
130 // https://golang.org/issue/25189
131 b.Run("Value", func(b *testing.B) {
132 b.ReportAllocs()
133 for i := 0; i < b.N; i++ {
134 sink2 = ValueOf(string(testdata[:len(testdata)%(i+1)]))
135 }
136 })
137
138 // Interface measures the time to store a string into an interface.
139 b.Run("Interface", func(b *testing.B) {
140 b.ReportAllocs()
141 for i := 0; i < b.N; i++ {
142 sink3 = string(testdata[:len(testdata)%(i+1)])
143 }
144 })
145
146 _, _, _ = sink1, sink2, sink3
147}