github.com/segmentio/encoding@v0.4.0/thrift/thrift_test.go (about) 1 package thrift_test 2 3 import ( 4 "bytes" 5 "math" 6 "reflect" 7 "strings" 8 "testing" 9 10 "github.com/segmentio/encoding/thrift" 11 ) 12 13 var marshalTestValues = [...]struct { 14 scenario string 15 values []interface{} 16 }{ 17 { 18 scenario: "bool", 19 values: []interface{}{false, true}, 20 }, 21 22 { 23 scenario: "int", 24 values: []interface{}{ 25 int(0), 26 int(-1), 27 int(1), 28 }, 29 }, 30 31 { 32 scenario: "int8", 33 values: []interface{}{ 34 int8(0), 35 int8(-1), 36 int8(1), 37 int8(math.MinInt8), 38 int8(math.MaxInt8), 39 }, 40 }, 41 42 { 43 scenario: "int16", 44 values: []interface{}{ 45 int16(0), 46 int16(-1), 47 int16(1), 48 int16(math.MinInt16), 49 int16(math.MaxInt16), 50 }, 51 }, 52 53 { 54 scenario: "int32", 55 values: []interface{}{ 56 int32(0), 57 int32(-1), 58 int32(1), 59 int32(math.MinInt32), 60 int32(math.MaxInt32), 61 }, 62 }, 63 64 { 65 scenario: "int64", 66 values: []interface{}{ 67 int64(0), 68 int64(-1), 69 int64(1), 70 int64(math.MinInt64), 71 int64(math.MaxInt64), 72 }, 73 }, 74 75 { 76 scenario: "string", 77 values: []interface{}{ 78 "", 79 "A", 80 "1234567890", 81 strings.Repeat("qwertyuiop", 100), 82 }, 83 }, 84 85 { 86 scenario: "[]byte", 87 values: []interface{}{ 88 []byte(""), 89 []byte("A"), 90 []byte("1234567890"), 91 bytes.Repeat([]byte("qwertyuiop"), 100), 92 }, 93 }, 94 95 { 96 scenario: "[]string", 97 values: []interface{}{ 98 []string{}, 99 []string{"A"}, 100 []string{"hello", "world", "!!!"}, 101 []string{"0", "1", "3", "4", "5", "6", "7", "8", "9"}, 102 }, 103 }, 104 105 { 106 scenario: "map[string]int", 107 values: []interface{}{ 108 map[string]int{}, 109 map[string]int{"A": 1}, 110 map[string]int{"hello": 1, "world": 2, "answer": 42}, 111 }, 112 }, 113 114 { 115 scenario: "map[int64]struct{}", 116 values: []interface{}{ 117 map[int64]struct{}{}, 118 map[int64]struct{}{0: {}, 1: {}, 2: {}}, 119 }, 120 }, 121 122 { 123 scenario: "[]map[string]struct{}", 124 values: []interface{}{ 125 []map[string]struct{}{}, 126 []map[string]struct{}{{}, {"A": {}, "B": {}, "C": {}}}, 127 }, 128 }, 129 130 { 131 scenario: "struct{}", 132 values: []interface{}{struct{}{}}, 133 }, 134 135 { 136 scenario: "Point2D", 137 values: []interface{}{ 138 Point2D{}, 139 Point2D{X: 1}, 140 Point2D{Y: 2}, 141 Point2D{X: 3, Y: 4}, 142 }, 143 }, 144 145 { 146 scenario: "RecursiveStruct", 147 values: []interface{}{ 148 RecursiveStruct{}, 149 RecursiveStruct{Value: "hello"}, 150 RecursiveStruct{Value: "hello", Next: &RecursiveStruct{}}, 151 RecursiveStruct{Value: "hello", Next: &RecursiveStruct{Value: "world", Test: newBool(true)}}, 152 }, 153 }, 154 155 { 156 scenario: "StructWithEnum", 157 values: []interface{}{ 158 StructWithEnum{}, 159 StructWithEnum{Enum: 1}, 160 StructWithEnum{Enum: 2}, 161 }, 162 }, 163 164 { 165 scenario: "StructWithPointToPointerToBool", 166 values: []interface{}{ 167 StructWithPointerToPointerToBool{ 168 Test: newBoolPtr(true), 169 }, 170 }, 171 }, 172 173 { 174 scenario: "StructWithEmbeddedStrutPointerWithPointerToPointer", 175 values: []interface{}{ 176 StructWithEmbeddedStrutPointerWithPointerToPointer{ 177 StructWithPointerToPointerToBool: &StructWithPointerToPointerToBool{ 178 Test: newBoolPtr(true), 179 }, 180 }, 181 }, 182 }, 183 184 { 185 scenario: "Union", 186 values: []interface{}{ 187 Union{}, 188 Union{A: true, F: newBool(true)}, 189 Union{B: 42, F: newInt(42)}, 190 Union{C: "hello world!", F: newString("hello world!")}, 191 }, 192 }, 193 } 194 195 type Point2D struct { 196 X float64 `thrift:"1,required"` 197 Y float64 `thrift:"2,required"` 198 } 199 200 type RecursiveStruct struct { 201 Value string `thrift:"1"` 202 Next *RecursiveStruct `thrift:"2"` 203 Test *bool `thrift:"3"` 204 } 205 206 type StructWithEnum struct { 207 Enum int8 `thrift:"1,enum"` 208 } 209 210 type StructWithPointerToPointerToBool struct { 211 Test **bool `thrift:"1"` 212 } 213 214 type StructWithEmbeddedStrutPointerWithPointerToPointer struct { 215 *StructWithPointerToPointerToBool 216 } 217 218 type Union struct { 219 A bool `thrift:"1"` 220 B int `thrift:"2"` 221 C string `thrift:"3"` 222 F interface{} `thrift:",union"` 223 } 224 225 func newBool(b bool) *bool { return &b } 226 func newInt(i int) *int { return &i } 227 func newString(s string) *string { return &s } 228 229 func newBoolPtr(b bool) **bool { 230 p := newBool(b) 231 return &p 232 } 233 234 func TestMarshalUnmarshal(t *testing.T) { 235 for _, p := range protocols { 236 t.Run(p.name, func(t *testing.T) { testMarshalUnmarshal(t, p.proto) }) 237 } 238 } 239 240 func testMarshalUnmarshal(t *testing.T, p thrift.Protocol) { 241 for _, test := range marshalTestValues { 242 t.Run(test.scenario, func(t *testing.T) { 243 for _, value := range test.values { 244 b, err := thrift.Marshal(p, value) 245 if err != nil { 246 t.Fatal("marshal:", err) 247 } 248 249 v := reflect.New(reflect.TypeOf(value)) 250 if err := thrift.Unmarshal(p, b, v.Interface()); err != nil { 251 t.Fatal("unmarshal:", err) 252 } 253 254 if result := v.Elem().Interface(); !reflect.DeepEqual(value, result) { 255 t.Errorf("value mismatch:\nwant: %#v\ngot: %#v", value, result) 256 } 257 } 258 }) 259 } 260 } 261 262 func BenchmarkMarshal(b *testing.B) { 263 for _, p := range protocols { 264 b.Run(p.name, func(b *testing.B) { benchmarkMarshal(b, p.proto) }) 265 } 266 } 267 268 type BenchmarkEncodeType struct { 269 Name string `thrift:"1"` 270 Question string `thrift:"2"` 271 Answer string `thrift:"3"` 272 Sub *BenchmarkEncodeType `thrift:"4"` 273 } 274 275 func benchmarkMarshal(b *testing.B, p thrift.Protocol) { 276 buf := new(bytes.Buffer) 277 enc := thrift.NewEncoder(p.NewWriter(buf)) 278 val := &BenchmarkEncodeType{ 279 Name: "Luke", 280 Question: "How are you?", 281 Answer: "42", 282 Sub: &BenchmarkEncodeType{ 283 Name: "Leia", 284 Question: "?", 285 Answer: "whatever", 286 }, 287 } 288 289 for i := 0; i < b.N; i++ { 290 buf.Reset() 291 enc.Encode(val) 292 } 293 294 b.SetBytes(int64(buf.Len())) 295 } 296 297 func BenchmarkUnmarshal(b *testing.B) { 298 for _, p := range protocols { 299 b.Run(p.name, func(b *testing.B) { benchmarkUnmarshal(b, p.proto) }) 300 } 301 } 302 303 type BenchmarkDecodeType struct { 304 Name string `thrift:"1"` 305 Question string `thrift:"2"` 306 Answer string `thrift:"3"` 307 Sub *BenchmarkDecodeType `thrift:"4"` 308 } 309 310 func benchmarkUnmarshal(b *testing.B, p thrift.Protocol) { 311 buf, _ := thrift.Marshal(p, &BenchmarkDecodeType{ 312 Name: "Luke", 313 Question: "How are you?", 314 Answer: "42", 315 Sub: &BenchmarkDecodeType{ 316 Name: "Leia", 317 Question: "?", 318 Answer: "whatever", 319 }, 320 }) 321 322 rb := bytes.NewReader(nil) 323 dec := thrift.NewDecoder(p.NewReader(rb)) 324 val := &BenchmarkDecodeType{} 325 326 for i := 0; i < b.N; i++ { 327 rb.Reset(buf) 328 dec.Decode(val) 329 } 330 331 b.SetBytes(int64(len(buf))) 332 }