value_test.go 5.9 KB

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