123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- // Copyright 2018 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package protoreflect
- import (
- "bytes"
- "math"
- "reflect"
- "testing"
- )
- var (
- fakeMessage = new(struct{ Message })
- fakeList = new(struct{ List })
- fakeMap = new(struct{ Map })
- )
- func TestValue(t *testing.T) {
- tests := []struct {
- in Value
- want interface{}
- }{
- {in: Value{}},
- {in: ValueOf(nil)},
- {in: ValueOf(true), want: true},
- {in: ValueOf(int32(math.MaxInt32)), want: int32(math.MaxInt32)},
- {in: ValueOf(int64(math.MaxInt64)), want: int64(math.MaxInt64)},
- {in: ValueOf(uint32(math.MaxUint32)), want: uint32(math.MaxUint32)},
- {in: ValueOf(uint64(math.MaxUint64)), want: uint64(math.MaxUint64)},
- {in: ValueOf(float32(math.MaxFloat32)), want: float32(math.MaxFloat32)},
- {in: ValueOf(float64(math.MaxFloat64)), want: float64(math.MaxFloat64)},
- {in: ValueOf(string("hello")), want: string("hello")},
- {in: ValueOf([]byte("hello")), want: []byte("hello")},
- {in: ValueOf(fakeMessage), want: fakeMessage},
- {in: ValueOf(fakeList), want: fakeList},
- {in: ValueOf(fakeMap), want: fakeMap},
- }
- for _, tt := range tests {
- got := tt.in.Interface()
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("Value(%v).Interface() = %v, want %v", tt.in, got, tt.want)
- }
- if got := tt.in.IsValid(); got != (tt.want != nil) {
- t.Errorf("Value(%v).IsValid() = %v, want %v", tt.in, got, tt.want != nil)
- }
- switch want := tt.want.(type) {
- case int32:
- if got := tt.in.Int(); got != int64(want) {
- t.Errorf("Value(%v).Int() = %v, want %v", tt.in, got, tt.want)
- }
- case int64:
- if got := tt.in.Int(); got != int64(want) {
- t.Errorf("Value(%v).Int() = %v, want %v", tt.in, got, tt.want)
- }
- case uint32:
- if got := tt.in.Uint(); got != uint64(want) {
- t.Errorf("Value(%v).Uint() = %v, want %v", tt.in, got, tt.want)
- }
- case uint64:
- if got := tt.in.Uint(); got != uint64(want) {
- t.Errorf("Value(%v).Uint() = %v, want %v", tt.in, got, tt.want)
- }
- case float32:
- if got := tt.in.Float(); got != float64(want) {
- t.Errorf("Value(%v).Float() = %v, want %v", tt.in, got, tt.want)
- }
- case float64:
- if got := tt.in.Float(); got != float64(want) {
- t.Errorf("Value(%v).Float() = %v, want %v", tt.in, got, tt.want)
- }
- case string:
- if got := tt.in.String(); got != string(want) {
- t.Errorf("Value(%v).String() = %v, want %v", tt.in, got, tt.want)
- }
- case []byte:
- if got := tt.in.Bytes(); !bytes.Equal(got, want) {
- t.Errorf("Value(%v).Bytes() = %v, want %v", tt.in, got, tt.want)
- }
- case EnumNumber:
- if got := tt.in.Enum(); got != want {
- t.Errorf("Value(%v).Enum() = %v, want %v", tt.in, got, tt.want)
- }
- case Message:
- if got := tt.in.Message(); got != want {
- t.Errorf("Value(%v).Message() = %v, want %v", tt.in, got, tt.want)
- }
- case List:
- if got := tt.in.List(); got != want {
- t.Errorf("Value(%v).List() = %v, want %v", tt.in, got, tt.want)
- }
- case Map:
- if got := tt.in.Map(); got != want {
- t.Errorf("Value(%v).Map() = %v, want %v", tt.in, got, tt.want)
- }
- }
- }
- }
- func TestValueEqual(t *testing.T) {
- tests := []struct {
- x, y Value
- want bool
- }{
- {Value{}, Value{}, true},
- {Value{}, ValueOfBool(true), false},
- {ValueOfBool(true), ValueOfBool(true), true},
- {ValueOfBool(true), ValueOfBool(false), false},
- {ValueOfBool(false), ValueOfInt32(0), false},
- {ValueOfInt32(0), ValueOfInt32(0), true},
- {ValueOfInt32(0), ValueOfInt32(1), false},
- {ValueOfInt32(0), ValueOfInt64(0), false},
- {ValueOfInt64(123), ValueOfInt64(123), true},
- {ValueOfFloat64(0), ValueOfFloat64(0), true},
- {ValueOfFloat64(math.NaN()), ValueOfFloat64(math.NaN()), true},
- {ValueOfFloat64(math.NaN()), ValueOfFloat64(0), false},
- {ValueOfFloat64(math.Inf(1)), ValueOfFloat64(math.Inf(1)), true},
- {ValueOfFloat64(math.Inf(-1)), ValueOfFloat64(math.Inf(1)), false},
- {ValueOfBytes(nil), ValueOfBytes(nil), true},
- {ValueOfBytes(nil), ValueOfBytes([]byte{}), true},
- {ValueOfBytes(nil), ValueOfBytes([]byte{1}), false},
- {ValueOfEnum(0), ValueOfEnum(0), true},
- {ValueOfEnum(0), ValueOfEnum(1), false},
- {ValueOfBool(false), ValueOfMessage(fakeMessage), false},
- {ValueOfMessage(fakeMessage), ValueOfList(fakeList), false},
- {ValueOfList(fakeList), ValueOfMap(fakeMap), false},
- {ValueOfMap(fakeMap), ValueOfMessage(fakeMessage), false},
- // Composite types are not tested here.
- // See proto.TestEqual.
- }
- for _, tt := range tests {
- got := tt.x.Equal(tt.y)
- if got != tt.want {
- t.Errorf("(%v).Equal(%v) = %v, want %v", tt.x, tt.y, got, tt.want)
- }
- }
- }
- func BenchmarkValue(b *testing.B) {
- const testdata = "The quick brown fox jumped over the lazy dog."
- var sink1 string
- var sink2 Value
- var sink3 interface{}
- // Baseline measures the time to store a string into a native variable.
- b.Run("Baseline", func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- sink1 = testdata[:len(testdata)%(i+1)]
- }
- })
- // Inline measures the time to store a string into a Value,
- // assuming that the compiler could inline the ValueOf function call.
- b.Run("Inline", func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- sink2 = valueOfString(testdata[:len(testdata)%(i+1)])
- }
- })
- // Value measures the time to store a string into a Value using the general
- // ValueOf function call. This should be identical to Inline.
- //
- // NOTE: As of Go1.11, this is not as efficient as Inline due to the lack
- // of some compiler optimizations:
- // https://golang.org/issue/22310
- // https://golang.org/issue/25189
- b.Run("Value", func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- sink2 = ValueOf(string(testdata[:len(testdata)%(i+1)]))
- }
- })
- // Interface measures the time to store a string into an interface.
- b.Run("Interface", func(b *testing.B) {
- b.ReportAllocs()
- for i := 0; i < b.N; i++ {
- sink3 = string(testdata[:len(testdata)%(i+1)])
- }
- })
- _, _, _ = sink1, sink2, sink3
- }
|