github.com/segmentio/encoding@v0.4.0/proto/proto_test.go (about) 1 package proto 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math" 7 "os" 8 "reflect" 9 "testing" 10 ) 11 12 func TestEncodeDecodeVarint(t *testing.T) { 13 b := [8]byte{} 14 15 n, err := encodeVarint(b[:], 42) 16 if err != nil { 17 t.Fatal(err) 18 } 19 20 v, n2, err := decodeVarint(b[:n]) 21 if err != nil { 22 t.Fatal(err) 23 } 24 if v != 42 { 25 t.Errorf("decoded value mismatch: want %d, got %d", 42, v) 26 } 27 if n2 != n { 28 t.Errorf("decoded byte count mismatch: want %d, got %d", n, n2) 29 } 30 } 31 32 func TestEncodeDecodeVarintZigZag(t *testing.T) { 33 b := [8]byte{} 34 35 n, err := encodeVarintZigZag(b[:], -42) 36 if err != nil { 37 t.Fatal(err) 38 } 39 40 v, n2, err := decodeVarintZigZag(b[:n]) 41 if err != nil { 42 t.Fatal(err) 43 } 44 if v != -42 { 45 t.Errorf("decoded value mismatch: want %d, got %d", -42, v) 46 } 47 if n2 != n { 48 t.Errorf("decoded byte count mismatch: want %d, got %d", n, n2) 49 } 50 } 51 52 func TestEncodeDecodeTag(t *testing.T) { 53 b := [8]byte{} 54 55 n, err := encodeTag(b[:], 1, varint) 56 if err != nil { 57 t.Fatal(err) 58 } 59 60 num, typ, n2, err := decodeTag(b[:n]) 61 if err != nil { 62 t.Fatal(err) 63 } 64 if num != 1 { 65 t.Errorf("decoded field number mismatch: want %d, got %d", 1, num) 66 } 67 if typ != varint { 68 t.Errorf("decoded wire type mismatch: want %d, got %d", varint, typ) 69 } 70 if n2 != n { 71 t.Errorf("decoded byte count mismatch: want %d, got %d", n, n2) 72 } 73 } 74 75 type key struct { 76 Hi uint64 77 Lo uint64 78 } 79 80 type message struct { 81 A int 82 B int 83 C int 84 S submessage 85 } 86 87 type submessage struct { 88 X string 89 Y string 90 } 91 92 type structWithMap struct { 93 M map[int]string 94 } 95 96 type custom [16]byte 97 98 func (c *custom) Size() int { return len(c) } 99 100 func (c *custom) MarshalTo(b []byte) (int, error) { 101 return copy(b, c[:]), nil 102 } 103 104 func (c *custom) Unmarshal(b []byte) error { 105 copy(c[:], b) 106 return nil 107 } 108 109 type messageWithRawMessage struct { 110 Raw RawMessage 111 } 112 113 type messageWithCustomField struct { 114 Custom custom 115 } 116 117 func TestMarshalUnmarshal(t *testing.T) { 118 intVal := 42 119 values := []interface{}{ 120 // bool 121 true, 122 false, 123 124 // zig-zag varint 125 0, 126 1, 127 1234567890, 128 -1, 129 -1234567890, 130 131 // sfixed32 132 int32(0), 133 int32(math.MinInt32), 134 int32(math.MaxInt32), 135 136 // sfixed64 137 int64(0), 138 int64(math.MinInt64), 139 int64(math.MaxInt64), 140 141 // varint 142 uint(0), 143 uint(1), 144 uint(1234567890), 145 146 // fixed32 147 uint32(0), 148 uint32(1234567890), 149 150 // fixed64 151 uint64(0), 152 uint64(1234567890), 153 154 // float 155 float32(0), 156 float32(math.Copysign(0, -1)), 157 float32(0.1234), 158 159 // double 160 float64(0), 161 float64(math.Copysign(0, -1)), 162 float64(0.1234), 163 164 // string 165 "", 166 "A", 167 "Hello World!", 168 169 // bytes 170 ([]byte)(nil), 171 []byte(""), 172 []byte("A"), 173 []byte("Hello World!"), 174 175 // messages 176 struct{ B bool }{B: false}, 177 struct{ B bool }{B: true}, 178 179 struct{ I int }{I: 0}, 180 struct{ I int }{I: 1}, 181 182 struct{ I32 int32 }{I32: 0}, 183 struct{ I32 int32 }{I32: -1234567890}, 184 185 struct{ I64 int64 }{I64: 0}, 186 struct{ I64 int64 }{I64: -1234567890}, 187 188 struct{ U int }{U: 0}, 189 struct{ U int }{U: 1}, 190 191 struct{ U32 uint32 }{U32: 0}, 192 struct{ U32 uint32 }{U32: 1234567890}, 193 194 struct{ U64 uint64 }{U64: 0}, 195 struct{ U64 uint64 }{U64: 1234567890}, 196 197 struct{ F32 float32 }{F32: 0}, 198 struct{ F32 float32 }{F32: 0.1234}, 199 200 struct{ F64 float64 }{F64: 0}, 201 struct{ F64 float64 }{F64: 0.1234}, 202 203 struct{ S string }{S: ""}, 204 struct{ S string }{S: "E"}, 205 206 struct{ B []byte }{B: nil}, 207 struct{ B []byte }{B: []byte{}}, 208 struct{ B []byte }{B: []byte{1, 2, 3}}, 209 210 &message{ 211 A: 1, 212 B: 2, 213 C: 3, 214 S: submessage{ 215 X: "hello", 216 Y: "world", 217 }, 218 }, 219 220 struct { 221 Min int64 `protobuf:"zigzag64,1,opt,name=min,proto3"` 222 Max int64 `protobuf:"zigzag64,2,opt,name=min,proto3"` 223 }{Min: math.MinInt64, Max: math.MaxInt64}, 224 225 // pointers 226 struct{ M *message }{M: nil}, 227 struct { 228 M1 *message 229 M2 *message 230 M3 *message 231 }{ 232 M1: &message{A: 10, B: 100, C: 1000}, 233 M2: &message{S: submessage{X: "42"}}, 234 }, 235 236 // byte arrays 237 [0]byte{}, 238 [8]byte{}, 239 [16]byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}, 240 &[...]byte{}, 241 &[...]byte{3, 2, 1}, 242 243 // slices (repeated) 244 struct{ S []int }{S: nil}, 245 struct{ S []int }{S: []int{0}}, 246 struct{ S []int }{S: []int{0, 0, 0}}, 247 struct{ S []int }{S: []int{1, 2, 3}}, 248 struct{ S []string }{S: nil}, 249 struct{ S []string }{S: []string{""}}, 250 struct{ S []string }{S: []string{"A", "B", "C"}}, 251 struct{ K []key }{ 252 K: []key{ 253 {Hi: 0, Lo: 0}, 254 {Hi: 0, Lo: 1}, 255 {Hi: 0, Lo: 2}, 256 {Hi: 0, Lo: 3}, 257 {Hi: 0, Lo: 4}, 258 }, 259 }, 260 261 // maps (repeated) 262 struct{ M map[int]string }{}, 263 struct{ M map[int]string }{ 264 M: map[int]string{0: ""}, 265 }, 266 struct{ M map[int]string }{ 267 M: map[int]string{0: "A", 1: "B", 2: "C"}, 268 }, 269 &struct{ M map[int]string }{ 270 M: map[int]string{0: "A", 1: "B", 2: "C"}, 271 }, 272 struct { 273 M1 map[int]int 274 M2 map[string]string 275 M3 map[string]message 276 M4 map[string]*message 277 M5 map[key]uint 278 }{ 279 M1: map[int]int{0: 1}, 280 M2: map[string]string{"": "A"}, 281 M3: map[string]message{ 282 "m0": message{}, 283 "m1": message{A: 42}, 284 "m3": message{S: submessage{X: "X", Y: "Y"}}, 285 }, 286 M4: map[string]*message{ 287 "m0": &message{}, 288 "m1": &message{A: 42}, 289 "m3": &message{S: submessage{X: "X", Y: "Y"}}, 290 }, 291 M5: map[key]uint{ 292 key{Hi: 0, Lo: 0}: 0, 293 key{Hi: 1, Lo: 0}: 1, 294 key{Hi: 0, Lo: 1}: 2, 295 key{Hi: math.MaxUint64, Lo: math.MaxUint64}: 3, 296 }, 297 }, 298 299 // more complex inlined types use cases 300 struct{ I *int }{}, 301 struct{ I *int }{I: new(int)}, 302 struct{ I *int }{I: &intVal}, 303 struct{ M *message }{}, 304 struct{ M *message }{M: new(message)}, 305 struct{ M map[int]int }{}, 306 struct{ M map[int]int }{M: map[int]int{}}, 307 struct{ S structWithMap }{ 308 S: structWithMap{ 309 M: map[int]string{0: "A", 1: "B", 2: "C"}, 310 }, 311 }, 312 &struct{ S structWithMap }{ 313 S: structWithMap{ 314 M: map[int]string{0: "A", 1: "B", 2: "C"}, 315 }, 316 }, 317 318 // raw messages 319 RawMessage(nil), 320 RawMessage{0x08, 0x96, 0x01}, 321 messageWithRawMessage{ 322 Raw: RawMessage{1, 2, 3, 4}, 323 }, 324 struct { 325 A int 326 B string 327 C RawMessage 328 }{A: 42, B: "Hello World!", C: RawMessage{1, 2, 3, 4}}, 329 330 // custom messages 331 custom{}, 332 custom{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 333 messageWithCustomField{ 334 Custom: custom{1: 42}, 335 }, 336 struct { 337 A int 338 B string 339 C custom 340 }{A: 42, B: "Hello World!", C: custom{1: 42}}, 341 } 342 343 for _, v := range values { 344 t.Run(fmt.Sprintf("%T/%+v", v, v), func(t *testing.T) { 345 n := Size(v) 346 347 b, err := Marshal(v) 348 if err != nil { 349 t.Fatal(err) 350 } 351 if n != len(b) { 352 t.Fatalf("value size and buffer length mismatch (%d != %d)", n, len(b)) 353 } 354 355 p := reflect.New(reflect.TypeOf(v)) 356 if err := Unmarshal(b, p.Interface()); err != nil { 357 t.Fatal(err) 358 } 359 360 x := p.Elem().Interface() 361 if !reflect.DeepEqual(v, x) { 362 t.Errorf("values mismatch:\nexpected: %#v\nfound: %#v", v, x) 363 } 364 }) 365 } 366 } 367 368 func loadProtobuf(t *testing.T, fileName string) RawMessage { 369 b, err := os.ReadFile("fixtures/protobuf/" + fileName) 370 if err != nil { 371 t.Fatal(err) 372 } 373 return RawMessage(b) 374 } 375 376 func makeVarint(v uint64) []byte { 377 b := [12]byte{} 378 n := binary.PutUvarint(b[:], v) 379 return b[:n] 380 } 381 382 func makeFixed32(v uint32) []byte { 383 b := [4]byte{} 384 binary.LittleEndian.PutUint32(b[:], v) 385 return b[:] 386 } 387 388 func makeFixed64(v uint64) []byte { 389 b := [8]byte{} 390 binary.LittleEndian.PutUint64(b[:], v) 391 return b[:] 392 }