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