github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/encoder_record_test.go (about)

     1  package avro_test
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/hamba/avro/v2"
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func TestEncoder_RecordStruct(t *testing.T) {
    13  	defer ConfigTeardown()
    14  
    15  	schema := `{
    16  	"type": "record",
    17  	"name": "test",
    18  	"fields" : [
    19  		{"name": "a", "type": "long"},
    20  	    {"name": "b", "type": "string"}
    21  	]
    22  }`
    23  	obj := TestRecord{A: 27, B: "foo"}
    24  	buf := &bytes.Buffer{}
    25  	enc, err := avro.NewEncoder(schema, buf)
    26  	require.NoError(t, err)
    27  
    28  	err = enc.Encode(obj)
    29  
    30  	require.NoError(t, err)
    31  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
    32  }
    33  
    34  func TestEncoder_RecordStructPtr(t *testing.T) {
    35  	defer ConfigTeardown()
    36  
    37  	schema := `{
    38  	"type": "record",
    39  	"name": "test",
    40  	"fields" : [
    41  		{"name": "a", "type": "long"},
    42  	    {"name": "b", "type": "string"}
    43  	]
    44  }`
    45  	obj := &TestRecord{A: 27, B: "foo"}
    46  	buf := &bytes.Buffer{}
    47  	enc, err := avro.NewEncoder(schema, buf)
    48  	require.NoError(t, err)
    49  
    50  	err = enc.Encode(obj)
    51  
    52  	require.NoError(t, err)
    53  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
    54  }
    55  
    56  func TestEncoder_RecordStructPtrNil(t *testing.T) {
    57  	defer ConfigTeardown()
    58  
    59  	schema := `{
    60  	"type": "record",
    61  	"name": "test",
    62  	"fields" : [
    63  		{"name": "a", "type": "long"},
    64  	    {"name": "b", "type": "string"}
    65  	]
    66  }`
    67  	var obj *TestRecord
    68  	buf := &bytes.Buffer{}
    69  	enc, err := avro.NewEncoder(schema, buf)
    70  	require.NoError(t, err)
    71  
    72  	err = enc.Encode(obj)
    73  
    74  	assert.Error(t, err)
    75  }
    76  
    77  func TestEncoder_RecordStructMissingRequiredField(t *testing.T) {
    78  	defer ConfigTeardown()
    79  
    80  	schema := `{
    81  	"type": "record",
    82  	"name": "test",
    83  	"fields" : [
    84  		{"name": "a", "type": "long"},
    85  	    {"name": "b", "type": "string"}
    86  	]
    87  }`
    88  	obj := TestPartialRecord{B: "foo"}
    89  	buf := &bytes.Buffer{}
    90  	enc, err := avro.NewEncoder(schema, buf)
    91  	require.NoError(t, err)
    92  
    93  	err = enc.Encode(obj)
    94  
    95  	assert.Error(t, err)
    96  }
    97  
    98  func TestEncoder_RecordStructWithDefault(t *testing.T) {
    99  	defer ConfigTeardown()
   100  
   101  	schema := `{
   102  	"type": "record",
   103  	"name": "test",
   104  	"fields" : [
   105  		{"name": "a", "type": "long", "default": 27},
   106  	    {"name": "b", "type": "string"}
   107  	]
   108  }`
   109  	obj := TestPartialRecord{B: "foo"}
   110  	buf := &bytes.Buffer{}
   111  	enc, err := avro.NewEncoder(schema, buf)
   112  	require.NoError(t, err)
   113  
   114  	err = enc.Encode(obj)
   115  
   116  	require.NoError(t, err)
   117  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   118  }
   119  
   120  func TestEncoder_RecordStructPartialWithNullDefault(t *testing.T) {
   121  	defer ConfigTeardown()
   122  
   123  	schema := `{
   124  	"type": "record",
   125  	"name": "test",
   126  	"fields" : [
   127  		{"name": "a", "type": ["null", "string"], "default": null},
   128  	    {"name": "b", "type": "string"}
   129  	]
   130  }`
   131  	obj := TestPartialRecord{B: "foo"}
   132  	buf := &bytes.Buffer{}
   133  	enc, err := avro.NewEncoder(schema, buf)
   134  	require.NoError(t, err)
   135  
   136  	err = enc.Encode(obj)
   137  
   138  	require.NoError(t, err)
   139  	assert.Equal(t, []byte{0x00, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   140  }
   141  
   142  func TestEncoder_RecordStructPartialWithSubRecordDefault(t *testing.T) {
   143  	defer ConfigTeardown()
   144  
   145  	_, err := avro.Parse(`{
   146  		"type": "record",
   147  		"name": "test",
   148  		"fields" : [
   149  			{"name": "a", "type": "long"},
   150  			{"name": "b", "type": "string"}
   151  		]
   152  	}`)
   153  	require.NoError(t, err)
   154  
   155  	schema := `{
   156  		"type": "record",
   157  		"name": "parent",
   158  		"fields" : [
   159  			{
   160  				"name": "a",
   161  				"type": "test",
   162  				"default": {"a": 1000, "b": "def b"}
   163  			},
   164  			{"name": "b", "type": "string"}
   165  		]
   166  	}`
   167  	obj := TestPartialRecord{B: "foo"}
   168  	buf := &bytes.Buffer{}
   169  	enc, err := avro.NewEncoder(schema, buf)
   170  	require.NoError(t, err)
   171  
   172  	err = enc.Encode(obj)
   173  	require.NoError(t, err)
   174  
   175  	assert.Equal(t, []byte{0xd0, 0xf, 0xa, 0x64, 0x65, 0x66, 0x20, 0x62, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes())
   176  }
   177  
   178  func TestEncoder_RecordStructWithNullDefault(t *testing.T) {
   179  	defer ConfigTeardown()
   180  
   181  	schema := `{
   182  	"type": "record",
   183  	"name": "test",
   184  	"fields" : [
   185  		{"name": "a", "type": "null", "default": null},
   186  	    {"name": "b", "type": "string"}
   187  	]
   188  }`
   189  	obj := TestPartialRecord{B: "foo"}
   190  	buf := &bytes.Buffer{}
   191  	enc, err := avro.NewEncoder(schema, buf)
   192  	require.NoError(t, err)
   193  
   194  	err = enc.Encode(obj)
   195  
   196  	require.NoError(t, err)
   197  	assert.Equal(t, []byte{0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   198  }
   199  
   200  func TestEncoder_RecordStructFieldError(t *testing.T) {
   201  	defer ConfigTeardown()
   202  
   203  	schema := `{
   204  	"type": "record",
   205  	"name": "test",
   206  	"fields" : [
   207  		{"name": "a", "type": "string"},
   208  	    {"name": "b", "type": "string"}
   209  	]
   210  }`
   211  	obj := TestRecord{A: 27, B: "foo"}
   212  	buf := &bytes.Buffer{}
   213  	enc, err := avro.NewEncoder(schema, buf)
   214  	require.NoError(t, err)
   215  
   216  	err = enc.Encode(obj)
   217  
   218  	assert.Error(t, err)
   219  }
   220  
   221  func TestEncoder_RecordEmbeddedStruct(t *testing.T) {
   222  	defer ConfigTeardown()
   223  
   224  	schema := `{
   225  	"type": "record",
   226  	"name": "test",
   227  	"fields" : [
   228  		{"name": "a", "type": "long"},
   229  	    {"name": "b", "type": "string"},
   230  	    {"name": "c", "type": "string"}
   231  	]
   232  }`
   233  	obj := TestEmbeddedRecord{TestEmbed: TestEmbed{A: 27, B: "foo"}, C: "bar"}
   234  	buf := &bytes.Buffer{}
   235  	enc, err := avro.NewEncoder(schema, buf)
   236  	require.NoError(t, err)
   237  
   238  	err = enc.Encode(obj)
   239  
   240  	require.NoError(t, err)
   241  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x06, 0x62, 0x61, 0x72}, buf.Bytes())
   242  }
   243  
   244  func TestEncoder_RecordEmbeddedPtrStruct(t *testing.T) {
   245  	defer ConfigTeardown()
   246  
   247  	schema := `{
   248  	"type": "record",
   249  	"name": "test",
   250  	"fields" : [
   251  		{"name": "a", "type": "long"},
   252  	    {"name": "b", "type": "string"},
   253  	    {"name": "c", "type": "string"}
   254  	]
   255  }`
   256  	obj := TestEmbeddedPtrRecord{TestEmbed: &TestEmbed{A: 27, B: "foo"}, C: "bar"}
   257  	buf := &bytes.Buffer{}
   258  	enc, err := avro.NewEncoder(schema, buf)
   259  	require.NoError(t, err)
   260  
   261  	err = enc.Encode(obj)
   262  
   263  	require.NoError(t, err)
   264  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x06, 0x62, 0x61, 0x72}, buf.Bytes())
   265  }
   266  
   267  func TestEncoder_RecordEmbeddedPtrStructNull(t *testing.T) {
   268  	defer ConfigTeardown()
   269  
   270  	schema := `{
   271  	"type": "record",
   272  	"name": "test",
   273  	"fields" : [
   274  		{"name": "a", "type": "long"},
   275  	    {"name": "b", "type": "string"},
   276  	    {"name": "c", "type": "string"}
   277  	]
   278  }`
   279  	obj := TestEmbeddedPtrRecord{C: "foo"}
   280  	buf := &bytes.Buffer{}
   281  	enc, err := avro.NewEncoder(schema, buf)
   282  	require.NoError(t, err)
   283  
   284  	err = enc.Encode(obj)
   285  
   286  	assert.Error(t, err)
   287  }
   288  
   289  func TestEncoder_RecordEmbeddedIntStruct(t *testing.T) {
   290  	defer ConfigTeardown()
   291  
   292  	schema := `{
   293  	"type": "record",
   294  	"name": "test",
   295  	"fields" : [
   296  		{"name": "a", "type": "long"},
   297  	    {"name": "b", "type": "string"}
   298  	]
   299  }`
   300  	obj := TestEmbeddedIntRecord{TestEmbedInt: 27, B: "foo"}
   301  	buf := &bytes.Buffer{}
   302  	enc, err := avro.NewEncoder(schema, buf)
   303  	require.NoError(t, err)
   304  
   305  	err = enc.Encode(obj)
   306  
   307  	assert.Error(t, err)
   308  }
   309  
   310  func TestEncoder_RecordUnexportedStruct(t *testing.T) {
   311  	defer ConfigTeardown()
   312  
   313  	schema := `{
   314  	"type": "record",
   315  	"name": "test",
   316  	"fields" : [
   317  		{"name": "a", "type": "long"},
   318  	    {"name": "b", "type": "string"}
   319  	]
   320  }`
   321  	obj := TestUnexportedRecord{A: 27, b: "foo"}
   322  	buf := &bytes.Buffer{}
   323  	enc, err := avro.NewEncoder(schema, buf)
   324  	require.NoError(t, err)
   325  
   326  	err = enc.Encode(obj)
   327  
   328  	assert.Error(t, err)
   329  }
   330  
   331  func TestEncoder_RecordMap(t *testing.T) {
   332  	defer ConfigTeardown()
   333  
   334  	schema := `{
   335  	"type": "record",
   336  	"name": "test",
   337  	"fields" : [
   338  		{"name": "a", "type": "long"},
   339  	    {"name": "b", "type": "string"}
   340  	]
   341  }`
   342  	obj := map[string]any{"a": int64(27), "b": "foo"}
   343  	buf := &bytes.Buffer{}
   344  	enc, err := avro.NewEncoder(schema, buf)
   345  	require.NoError(t, err)
   346  
   347  	err = enc.Encode(obj)
   348  
   349  	require.NoError(t, err)
   350  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   351  }
   352  
   353  func TestEncoder_RecordMapNested(t *testing.T) {
   354  	defer ConfigTeardown()
   355  
   356  	schema := `{
   357  	"type": "record",
   358  	"name": "parent",
   359  	"fields" : [
   360  		{"name": "a", "type": {
   361  			"type": "record",
   362  			"name": "test",
   363  			"fields" : [
   364  				{"name": "a", "type": "long"},
   365  	    		{"name": "b", "type": "string"}
   366  			]}
   367  		},
   368  	    {"name": "b", "type": "string"}
   369  	]
   370  }`
   371  	obj := map[string]any{"a": map[string]any{
   372  		"a": int64(27),
   373  		"b": "bar",
   374  	}, "b": "foo"}
   375  	buf := &bytes.Buffer{}
   376  	enc, err := avro.NewEncoder(schema, buf)
   377  	require.NoError(t, err)
   378  
   379  	err = enc.Encode(obj)
   380  
   381  	require.NoError(t, err)
   382  	assert.Equal(t, []byte{0x36, 0x6, 0x62, 0x61, 0x72, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes())
   383  }
   384  
   385  func TestEncoder_RecordMapNilValue(t *testing.T) {
   386  	defer ConfigTeardown()
   387  
   388  	schema := `{
   389  	"type": "record",
   390  	"name": "test",
   391  	"fields" : [
   392  		{"name": "a", "type": "long"},
   393  	    {"name": "b", "type": "string"}
   394  	]
   395  }`
   396  	obj := map[string]any{"a": int64(27), "b": nil}
   397  	buf := &bytes.Buffer{}
   398  	enc, err := avro.NewEncoder(schema, buf)
   399  	require.NoError(t, err)
   400  
   401  	err = enc.Encode(obj)
   402  
   403  	assert.Error(t, err)
   404  }
   405  
   406  func TestEncoder_RecordMapMissingRequiredField(t *testing.T) {
   407  	defer ConfigTeardown()
   408  
   409  	schema := `{
   410  	"type": "record",
   411  	"name": "test",
   412  	"fields" : [
   413  		{"name": "a", "type": "long"},
   414  	    {"name": "b", "type": "string"}
   415  	]
   416  }`
   417  	obj := map[string]any{"b": "foo"}
   418  	buf := &bytes.Buffer{}
   419  	enc, err := avro.NewEncoder(schema, buf)
   420  	require.NoError(t, err)
   421  
   422  	err = enc.Encode(obj)
   423  
   424  	assert.Error(t, err)
   425  }
   426  
   427  func TestEncoder_RecordMapWithDefault(t *testing.T) {
   428  	defer ConfigTeardown()
   429  
   430  	schema := `{
   431  	"type": "record",
   432  	"name": "test",
   433  	"fields" : [
   434  		{"name": "a", "type": "long", "default": 27},
   435  	    {"name": "b", "type": "string"}
   436  	]
   437  }`
   438  	obj := map[string]any{"b": "foo"}
   439  	buf := &bytes.Buffer{}
   440  	enc, err := avro.NewEncoder(schema, buf)
   441  	require.NoError(t, err)
   442  
   443  	err = enc.Encode(obj)
   444  
   445  	require.NoError(t, err)
   446  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   447  }
   448  
   449  func TestEncoder_RecordMapWithSubRecordDefault(t *testing.T) {
   450  	defer ConfigTeardown()
   451  
   452  	_, err := avro.Parse(`{
   453  		"type": "record",
   454  		"name": "test",
   455  		"fields" : [
   456  			{"name": "a", "type": "long"},
   457  			{"name": "b", "type": "string"}
   458  		]
   459  	}`)
   460  	require.NoError(t, err)
   461  
   462  	schema := `{
   463  		"type": "record",
   464  		"name": "parent",
   465  		"fields" : [
   466  			{
   467  				"name": "a",
   468  				"type": "test",
   469  				"default": {"a": 1000, "b": "def b"}
   470  			},
   471  			{"name": "b", "type": "string"}
   472  		]
   473  	}`
   474  
   475  	obj := map[string]any{"b": "foo"}
   476  	buf := &bytes.Buffer{}
   477  	enc, err := avro.NewEncoder(schema, buf)
   478  	require.NoError(t, err)
   479  
   480  	err = enc.Encode(obj)
   481  	require.NoError(t, err)
   482  
   483  	assert.Equal(t, []byte{0xd0, 0xf, 0xa, 0x64, 0x65, 0x66, 0x20, 0x62, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes())
   484  }
   485  
   486  func TestEncoder_RecordMapWithNullDefault(t *testing.T) {
   487  	defer ConfigTeardown()
   488  
   489  	schema := `{
   490  	"type": "record",
   491  	"name": "test",
   492  	"fields" : [
   493  		{"name": "a", "type": "null", "default": null},
   494  	    {"name": "b", "type": "string"}
   495  	]
   496  }`
   497  	obj := map[string]any{"b": "foo"}
   498  	buf := &bytes.Buffer{}
   499  	enc, err := avro.NewEncoder(schema, buf)
   500  	require.NoError(t, err)
   501  
   502  	err = enc.Encode(obj)
   503  
   504  	require.NoError(t, err)
   505  	assert.Equal(t, []byte{0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   506  }
   507  
   508  func TestEncoder_RecordMapWithUnionNullDefault(t *testing.T) {
   509  	defer ConfigTeardown()
   510  
   511  	schema := `{
   512  	"type": "record",
   513  	"name": "test",
   514  	"fields" : [
   515  		{"name": "a", "type": ["null", "string"], "default": null},
   516  	    {"name": "b", "type": "string"}
   517  	]
   518  }`
   519  	obj := map[string]any{"b": "foo"}
   520  	buf := &bytes.Buffer{}
   521  	enc, err := avro.NewEncoder(schema, buf)
   522  	require.NoError(t, err)
   523  
   524  	err = enc.Encode(obj)
   525  
   526  	require.NoError(t, err)
   527  	assert.Equal(t, []byte{0x00, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   528  }
   529  
   530  func TestEncoder_RecordMapWithUnionStringDefault(t *testing.T) {
   531  	defer ConfigTeardown()
   532  
   533  	schema := `{
   534  	"type": "record",
   535  	"name": "test",
   536  	"fields" : [
   537  		{"name": "a", "type": ["string", "null"], "default": "test"},
   538  	    {"name": "b", "type": "string"}
   539  	]
   540  }`
   541  	obj := map[string]any{"b": "foo"}
   542  	buf := &bytes.Buffer{}
   543  	enc, err := avro.NewEncoder(schema, buf)
   544  	require.NoError(t, err)
   545  
   546  	err = enc.Encode(obj)
   547  
   548  	require.NoError(t, err)
   549  	assert.Equal(t, []byte{0x0, 0x8, 0x74, 0x65, 0x73, 0x74, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes())
   550  }
   551  
   552  func TestEncoder_RecordMapInvalidKeyType(t *testing.T) {
   553  	defer ConfigTeardown()
   554  
   555  	schema := `{
   556  	"type": "record",
   557  	"name": "test",
   558  	"fields" : [
   559  		{"name": "a", "type": "null", "default": null},
   560  	    {"name": "b", "type": "string"}
   561  	]
   562  }`
   563  	obj := map[int]any{1: int64(27), 2: "foo"}
   564  	buf := &bytes.Buffer{}
   565  	enc, err := avro.NewEncoder(schema, buf)
   566  	require.NoError(t, err)
   567  
   568  	err = enc.Encode(obj)
   569  
   570  	assert.Error(t, err)
   571  }
   572  
   573  func TestEncoder_RecordMapInvalidValueType(t *testing.T) {
   574  	defer ConfigTeardown()
   575  
   576  	schema := `{
   577  	"type": "record",
   578  	"name": "test",
   579  	"fields" : [
   580  		{"name": "a", "type": "null", "default": null},
   581  	    {"name": "b", "type": "string"}
   582  	]
   583  }`
   584  	obj := map[string]string{"a": "test", "b": "foo"}
   585  	buf := &bytes.Buffer{}
   586  	enc, err := avro.NewEncoder(schema, buf)
   587  	require.NoError(t, err)
   588  
   589  	err = enc.Encode(obj)
   590  
   591  	assert.Error(t, err)
   592  }
   593  
   594  func TestEncoder_RefStruct(t *testing.T) {
   595  	defer ConfigTeardown()
   596  
   597  	schema := `{
   598  	"type": "record",
   599  	"name": "parent",
   600  	"fields" : [
   601  		{"name": "a", "type": {
   602  			"type": "record",
   603  			"name": "test",
   604  			"fields" : [
   605  				{"name": "a", "type": "long"},
   606  	    		{"name": "b", "type": "string"}
   607  			]}
   608  		},
   609  	    {"name": "b", "type": "test"}
   610  	]
   611  }`
   612  	obj := TestNestedRecord{
   613  		A: TestRecord{A: 27, B: "foo"},
   614  		B: TestRecord{A: 27, B: "foo"},
   615  	}
   616  	buf := &bytes.Buffer{}
   617  	enc, err := avro.NewEncoder(schema, buf)
   618  	require.NoError(t, err)
   619  
   620  	err = enc.Encode(obj)
   621  
   622  	require.NoError(t, err)
   623  	assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes())
   624  }