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  }