github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/writer_test.go (about) 1 package avro_test 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "testing" 8 9 "github.com/hamba/avro/v2" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestWriter_Reset(t *testing.T) { 15 var buf bytes.Buffer 16 w := avro.NewWriter(nil, 10) 17 w.Reset(&buf) 18 _, _ = w.Write([]byte("test")) 19 20 err := w.Flush() 21 22 require.NoError(t, err) 23 assert.Equal(t, []byte("test"), buf.Bytes()) 24 } 25 26 func TestWriter_Buffer(t *testing.T) { 27 w := avro.NewWriter(nil, 10) 28 _, _ = w.Write([]byte("test")) 29 30 assert.Equal(t, 4, w.Buffered()) 31 assert.Equal(t, []byte("test"), w.Buffer()) 32 } 33 34 func TestWriter_Flush(t *testing.T) { 35 var buf bytes.Buffer 36 w := avro.NewWriter(&buf, 10) 37 _, _ = w.Write([]byte("test")) 38 39 err := w.Flush() 40 41 require.NoError(t, err) 42 assert.Equal(t, []byte("test"), buf.Bytes()) 43 } 44 45 type shortWrite struct{} 46 47 func (shortWrite) Write(p []byte) (n int, err error) { return len(p) - 1, nil } // short write (breaks io.Writer contract; see io.ErrShortWrite) 48 49 func TestWriter_FlushShortWrite(t *testing.T) { 50 w := avro.NewWriter(shortWrite{}, 10) 51 _, _ = w.Write([]byte("test")) 52 53 err := w.Flush() 54 55 require.ErrorIs(t, err, io.ErrShortWrite) 56 } 57 58 func TestWriter_FlushNoWriter(t *testing.T) { 59 w := avro.NewWriter(nil, 10) 60 _, _ = w.Write([]byte("test")) 61 62 err := w.Flush() 63 64 assert.NoError(t, err) 65 } 66 67 func TestWriter_FlushReturnsWriterError(t *testing.T) { 68 var buf bytes.Buffer 69 w := avro.NewWriter(&buf, 10) 70 w.Error = errors.New("test") 71 72 err := w.Flush() 73 74 assert.Error(t, err) 75 } 76 77 func TestWriter_FlushReturnsUnderlyingWriterError(t *testing.T) { 78 w := avro.NewWriter(&errorWriter{}, 10) 79 _, _ = w.Write([]byte("test")) 80 81 err := w.Flush() 82 83 assert.Error(t, err) 84 assert.Error(t, w.Error) 85 } 86 87 func TestWriter_FlushReuseMemory(t *testing.T) { 88 var buf bytes.Buffer 89 w := avro.NewWriter(&buf, 10) 90 _, _ = w.Write(bytes.Repeat([]byte("test"), 10)) 91 92 bufAddr := &w.Buffer()[:1][0] // buffer alloc address 93 err := w.Flush() 94 bufAddr2 := &w.Buffer()[:1][0] 95 96 require.NoError(t, err) 97 98 assert.Equal(t, bufAddr, bufAddr2) 99 } 100 101 func TestWriter_Write(t *testing.T) { 102 w := avro.NewWriter(nil, 50) 103 104 _, _ = w.Write([]byte{0xBC, 0xDC, 0x06, 0x00, 0x10, 0x0A}) 105 106 assert.Equal(t, []byte{0xBC, 0xDC, 0x06, 0x00, 0x10, 0x0A}, w.Buffer()) 107 } 108 109 func TestWriter_WriteBool(t *testing.T) { 110 tests := []struct { 111 data bool 112 want []byte 113 }{ 114 { 115 data: false, 116 want: []byte{0x00}, 117 }, 118 { 119 data: true, 120 want: []byte{0x01}, 121 }, 122 } 123 124 for _, test := range tests { 125 w := avro.NewWriter(nil, 50) 126 127 w.WriteBool(test.data) 128 129 assert.Equal(t, test.want, w.Buffer()) 130 } 131 } 132 133 func TestWriter_WriteInt(t *testing.T) { 134 tests := []struct { 135 data int32 136 want []byte 137 }{ 138 { 139 data: 27, 140 want: []byte{0x36}, 141 }, 142 { 143 data: -8, 144 want: []byte{0x0F}, 145 }, 146 { 147 data: -1, 148 want: []byte{0x01}, 149 }, 150 { 151 data: 0, 152 want: []byte{0x00}, 153 }, 154 { 155 data: 1, 156 want: []byte{0x02}, 157 }, 158 { 159 data: -64, 160 want: []byte{0x7F}, 161 }, 162 { 163 data: 64, 164 want: []byte{0x80, 0x01}, 165 }, 166 { 167 data: 123456789, 168 want: []byte{0xAA, 0xB4, 0xDE, 0x75}, 169 }, 170 { 171 data: 987654321, 172 want: []byte{0xE2, 0xA2, 0xF3, 0xAD, 0x07}, 173 }, 174 } 175 176 for _, test := range tests { 177 w := avro.NewWriter(nil, 50) 178 179 w.WriteInt(test.data) 180 181 assert.Equal(t, test.want, w.Buffer()) 182 } 183 } 184 185 func TestWriter_WriteLong(t *testing.T) { 186 tests := []struct { 187 data int64 188 want []byte 189 }{ 190 { 191 data: 27, 192 want: []byte{0x36}, 193 }, 194 { 195 data: -8, 196 want: []byte{0x0F}, 197 }, 198 { 199 data: -1, 200 want: []byte{0x01}, 201 }, 202 { 203 data: 0, 204 want: []byte{0x00}, 205 }, 206 { 207 data: 1, 208 want: []byte{0x02}, 209 }, 210 { 211 data: -64, 212 want: []byte{0x7F}, 213 }, 214 { 215 data: 64, 216 want: []byte{0x80, 0x01}, 217 }, 218 { 219 data: 123456789, 220 want: []byte{0xAA, 0xB4, 0xDE, 0x75}, 221 }, 222 { 223 data: 987654321, 224 want: []byte{0xE2, 0xA2, 0xF3, 0xAD, 0x07}, 225 }, 226 { 227 data: 9223372036854775807, 228 want: []byte{0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, 229 }, 230 { 231 data: -9223372036854775808, 232 want: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01}, 233 }, 234 { 235 data: -5468631321897454687, 236 want: []byte{0xBD, 0xB1, 0xAE, 0xD4, 0xD2, 0xCD, 0xBD, 0xE4, 0x97, 0x01}, 237 }, 238 } 239 240 for _, test := range tests { 241 w := avro.NewWriter(nil, 50) 242 243 w.WriteLong(test.data) 244 245 assert.Equal(t, test.want, w.Buffer()) 246 } 247 } 248 249 func TestWriter_WriteFloat(t *testing.T) { 250 tests := []struct { 251 data float32 252 want []byte 253 }{ 254 { 255 data: 0.0, 256 want: []byte{0x00, 0x00, 0x00, 0x00}, 257 }, 258 { 259 data: 1.0, 260 want: []byte{0x00, 0x00, 0x80, 0x3F}, 261 }, 262 { 263 data: 1.15, 264 want: []byte{0x33, 0x33, 0x93, 0x3F}, 265 }, 266 { 267 data: -53.964, 268 want: []byte{0x23, 0xDB, 0x57, 0xC2}, 269 }, 270 { 271 data: -123456789.123, 272 want: []byte{0xA3, 0x79, 0xEB, 0xCC}, 273 }, 274 { 275 data: 987654.111115, 276 want: []byte{0x62, 0x20, 0x71, 0x49}, 277 }, 278 } 279 280 for _, test := range tests { 281 w := avro.NewWriter(nil, 50) 282 283 w.WriteFloat(test.data) 284 285 assert.Equal(t, test.want, w.Buffer()) 286 } 287 } 288 289 func TestWriter_WriteDouble(t *testing.T) { 290 tests := []struct { 291 data float64 292 want []byte 293 }{ 294 { 295 data: 0.0, 296 want: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 297 }, 298 { 299 data: 1.0, 300 want: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F}, 301 }, 302 { 303 data: 1.15, 304 want: []byte{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF2, 0x3F}, 305 }, 306 { 307 data: -53.964, 308 want: []byte{0x08, 0xAC, 0x1C, 0x5A, 0x64, 0xFB, 0x4A, 0xC0}, 309 }, 310 { 311 data: -123456789.123, 312 want: []byte{0xB6, 0xF3, 0x7D, 0x54, 0x34, 0x6F, 0x9D, 0xC1}, 313 }, 314 { 315 data: 987654.111115, 316 want: []byte{0xB6, 0x10, 0xE4, 0x38, 0x0C, 0x24, 0x2E, 0x41}, 317 }, 318 { 319 data: 123456789.123456789, 320 want: []byte{0x75, 0x6B, 0x7E, 0x54, 0x34, 0x6F, 0x9D, 0x41}, 321 }, 322 { 323 data: 9999999.99999999999999999999999, 324 want: []byte{0x00, 0x00, 0x00, 0x00, 0xD0, 0x12, 0x63, 0x41}, 325 }, 326 { 327 data: 916734926348163.01973408746523, 328 want: []byte{0x18, 0xFC, 0x1A, 0xDD, 0x1F, 0x0E, 0x0A, 0x43}, 329 }, 330 { 331 data: -267319348967891263.1928357138913857, 332 want: []byte{0x0A, 0x8F, 0xA6, 0x40, 0xAC, 0xAD, 0x8D, 0xC3}, 333 }, 334 } 335 336 for _, test := range tests { 337 w := avro.NewWriter(nil, 50) 338 339 w.WriteDouble(test.data) 340 341 assert.Equal(t, test.want, w.Buffer()) 342 } 343 } 344 345 func TestWriter_WriteBytes(t *testing.T) { 346 tests := []struct { 347 data []byte 348 want []byte 349 }{ 350 { 351 data: []byte{0x02}, 352 want: []byte{0x02, 0x02}, 353 }, 354 { 355 data: []byte{0x03, 0xFF}, 356 want: []byte{0x04, 0x03, 0xFF}, 357 }, 358 { 359 data: []byte{0xEC, 0xAB, 0x44, 0x00}, 360 want: []byte{0x08, 0xEC, 0xAB, 0x44, 0x00}, 361 }, 362 { 363 data: []byte{0xAC, 0xDC, 0x01, 0x00, 0x10, 0x0F}, 364 want: []byte{0x0C, 0xAC, 0xDC, 0x01, 0x00, 0x10, 0x0F}, 365 }, 366 } 367 368 for _, test := range tests { 369 w := avro.NewWriter(nil, 50) 370 371 w.WriteBytes(test.data) 372 373 assert.Equal(t, test.want, w.Buffer()) 374 } 375 } 376 377 func TestWriter_WriteString(t *testing.T) { 378 tests := []struct { 379 data string 380 want []byte 381 }{ 382 { 383 data: "", 384 want: []byte{0x00}, 385 }, 386 { 387 data: "foo", 388 want: []byte{0x06, 0x66, 0x6F, 0x6F}, 389 }, 390 { 391 data: "avro", 392 want: []byte{0x08, 0x61, 0x76, 0x72, 0x6F}, 393 }, 394 { 395 data: "apache", 396 want: []byte{0x0C, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65}, 397 }, 398 { 399 data: "oppan gangnam style!", 400 want: []byte{0x28, 0x6F, 0x70, 0x70, 0x61, 0x6E, 0x20, 0x67, 0x61, 0x6E, 0x67, 0x6E, 0x61, 0x6D, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x21}, 401 }, 402 { 403 data: "че-то по русски", 404 want: []byte{0x36, 0xD1, 0x87, 0xD0, 0xB5, 0x2D, 0xD1, 0x82, 0xD0, 0xBE, 0x20, 0xD0, 0xBF, 0xD0, 0xBE, 0x20, 0xD1, 0x80, 0xD1, 0x83, 0xD1, 0x81, 0xD1, 0x81, 0xD0, 0xBA, 0xD0, 0xB8}, 405 }, 406 { 407 data: "世界", 408 want: []byte{0x0C, 0xE4, 0xB8, 0x96, 0xE7, 0x95, 0x8C}, 409 }, 410 { 411 data: "!№;%:?*\"()@#$^&", 412 want: []byte{0x22, 0x21, 0xE2, 0x84, 0x96, 0x3B, 0x25, 0x3A, 0x3F, 0x2A, 0x22, 0x28, 0x29, 0x40, 0x23, 0x24, 0x5E, 0x26}, 413 }, 414 } 415 416 for _, test := range tests { 417 w := avro.NewWriter(nil, 50) 418 419 w.WriteString(test.data) 420 421 assert.Equal(t, test.want, w.Buffer()) 422 } 423 } 424 425 func TestWriter_WriteBlockHeader(t *testing.T) { 426 tests := []struct { 427 len int64 428 size int64 429 disableSize bool 430 want []byte 431 }{ 432 { 433 len: 64, 434 size: 0, 435 want: []byte{0x80, 0x01}, 436 }, 437 { 438 len: 64, 439 size: 64, 440 want: []byte{0x7F, 0x80, 0x01}, 441 }, 442 { 443 len: 64, 444 size: 64, 445 disableSize: true, 446 want: []byte{0x80, 0x01}, 447 }, 448 } 449 450 for _, test := range tests { 451 cfg := avro.Config{ 452 DisableBlockSizeHeader: test.disableSize, 453 }.Freeze() 454 455 w := avro.NewWriter(nil, 50, avro.WithWriterConfig(cfg)) 456 457 w.WriteBlockHeader(test.len, test.size) 458 459 assert.Equal(t, test.want, w.Buffer()) 460 } 461 } 462 463 func TestWriter_WriteBlockCB(t *testing.T) { 464 tests := []struct { 465 disableSize bool 466 writeCallback func(w *avro.Writer) int64 467 want []byte 468 wantLen int64 469 }{ 470 { 471 writeCallback: func(w *avro.Writer) int64 { 472 w.WriteString("foo") 473 w.WriteString("avro") 474 475 return 2 476 }, 477 want: []byte{0x03, 0x12, 0x06, 0x66, 0x6F, 0x6F, 0x08, 0x61, 0x76, 0x72, 0x6F}, 478 wantLen: 2, 479 }, 480 { 481 disableSize: true, 482 writeCallback: func(w *avro.Writer) int64 { 483 w.WriteString("foo") 484 w.WriteString("avro") 485 486 return 2 487 }, 488 want: []byte{0x04, 0x06, 0x66, 0x6F, 0x6F, 0x08, 0x61, 0x76, 0x72, 0x6F}, 489 wantLen: 2, 490 }, 491 } 492 493 for _, test := range tests { 494 cfg := avro.Config{ 495 DisableBlockSizeHeader: test.disableSize, 496 }.Freeze() 497 498 w := avro.NewWriter(nil, 50, avro.WithWriterConfig(cfg)) 499 500 wrote := w.WriteBlockCB(test.writeCallback) 501 502 assert.Equal(t, test.want, w.Buffer()) 503 assert.Equal(t, test.wantLen, wrote) 504 } 505 } 506 507 type errorWriter struct{} 508 509 func (errorWriter) Write(p []byte) (n int, err error) { 510 return 0, errors.New("test error") 511 }