value_test.go 4.4 KB

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