github.com/hamba/avro@v1.8.0/encoder_union_test.go (about)

     1  package avro_test
     2  
     3  import (
     4  	"bytes"
     5  	"math/big"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/hamba/avro"
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  func TestEncoder_UnionMap(t *testing.T) {
    14  	defer ConfigTeardown()
    15  
    16  	schema := `["null", "string"]`
    17  	buf := bytes.NewBuffer([]byte{})
    18  	enc, err := avro.NewEncoder(schema, buf)
    19  	assert.NoError(t, err)
    20  
    21  	err = enc.Encode(map[string]interface{}{"string": "foo"})
    22  
    23  	assert.NoError(t, err)
    24  	assert.Equal(t, []byte{0x02, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes())
    25  }
    26  
    27  func TestEncoder_UnionMapRecord(t *testing.T) {
    28  	defer ConfigTeardown()
    29  
    30  	schema := `["null", {
    31  	"type": "record",
    32  	"name": "test",
    33  	"fields" : [
    34  		{"name": "a", "type": ["string", "null"], "default": "test"},
    35  	    {"name": "b", "type": "string"}
    36  	]
    37  }]`
    38  	buf := bytes.NewBuffer([]byte{})
    39  	enc, err := avro.NewEncoder(schema, buf)
    40  	assert.NoError(t, err)
    41  
    42  	err = enc.Encode(map[string]interface{}{"test": map[string]interface{}{"b": "foo"}})
    43  
    44  	assert.NoError(t, err)
    45  	assert.Equal(t, []byte{0x02, 0x00, 0x08, 0x74, 0x65, 0x73, 0x74, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes())
    46  }
    47  
    48  func TestEncoder_UnionMapNamed(t *testing.T) {
    49  	defer ConfigTeardown()
    50  
    51  	schema := `["null", {"type":"enum", "name": "test", "symbols": ["foo", "bar"]}]`
    52  	buf := bytes.NewBuffer([]byte{})
    53  	enc, err := avro.NewEncoder(schema, buf)
    54  	assert.NoError(t, err)
    55  
    56  	err = enc.Encode(map[string]interface{}{"test": "bar"})
    57  
    58  	assert.NoError(t, err)
    59  	assert.Equal(t, []byte{0x02, 0x02}, buf.Bytes())
    60  }
    61  
    62  func TestEncoder_UnionMapNull(t *testing.T) {
    63  	defer ConfigTeardown()
    64  
    65  	schema := `["null", "string"]`
    66  	buf := bytes.NewBuffer([]byte{})
    67  	enc, err := avro.NewEncoder(schema, buf)
    68  	assert.NoError(t, err)
    69  
    70  	var m map[string]interface{}
    71  	err = enc.Encode(m)
    72  
    73  	assert.NoError(t, err)
    74  	assert.Equal(t, []byte{0x00}, buf.Bytes())
    75  }
    76  
    77  func TestEncoder_UnionMapMultipleEntries(t *testing.T) {
    78  	defer ConfigTeardown()
    79  
    80  	schema := `["null", "string", "int"]`
    81  	buf := bytes.NewBuffer([]byte{})
    82  	enc, err := avro.NewEncoder(schema, buf)
    83  	assert.NoError(t, err)
    84  
    85  	err = enc.Encode(map[string]interface{}{"string": "foo", "int": 27})
    86  
    87  	assert.Error(t, err)
    88  }
    89  
    90  func TestEncoder_UnionMapWithTime(t *testing.T) {
    91  	defer ConfigTeardown()
    92  
    93  	schema := `["null", {"type": "long", "logicalType": "timestamp-micros"}]`
    94  	buf := bytes.NewBuffer([]byte{})
    95  	enc, err := avro.NewEncoder(schema, buf)
    96  	assert.NoError(t, err)
    97  
    98  	m := map[string]interface{}{
    99  		"long.timestamp-micros": time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
   100  	}
   101  	err = enc.Encode(m)
   102  
   103  	assert.NoError(t, err)
   104  	assert.Equal(t, []byte{0x02, 0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05}, buf.Bytes())
   105  }
   106  
   107  func TestEncoder_UnionMapWithDuration(t *testing.T) {
   108  	defer ConfigTeardown()
   109  
   110  	schema := `["null", {"type": "int", "logicalType": "time-millis"}]`
   111  	buf := bytes.NewBuffer([]byte{})
   112  	enc, err := avro.NewEncoder(schema, buf)
   113  	assert.NoError(t, err)
   114  
   115  	m := map[string]interface{}{
   116  		"int.time-millis": 123456789 * time.Millisecond,
   117  	}
   118  	err = enc.Encode(m)
   119  
   120  	assert.NoError(t, err)
   121  	assert.Equal(t, []byte{0x02, 0xAA, 0xB4, 0xDE, 0x75}, buf.Bytes())
   122  }
   123  
   124  func TestEncoder_UnionMapWithDecimal(t *testing.T) {
   125  	defer ConfigTeardown()
   126  
   127  	t.Run("low scale", func(t *testing.T) {
   128  		schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}]`
   129  		buf := bytes.NewBuffer([]byte{})
   130  		enc, err := avro.NewEncoder(schema, buf)
   131  		assert.NoError(t, err)
   132  
   133  		m := map[string]interface{}{
   134  			"bytes.decimal": big.NewRat(1734, 5),
   135  		}
   136  		err = enc.Encode(m)
   137  
   138  		assert.NoError(t, err)
   139  		assert.Equal(t, []byte{0x02, 0x6, 0x00, 0x87, 0x78}, buf.Bytes())
   140  	})
   141  
   142  	t.Run("high scale", func(t *testing.T) {
   143  		schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 77, "scale": 38}]`
   144  		buf := bytes.NewBuffer([]byte{})
   145  		enc, err := avro.NewEncoder(schema, buf)
   146  		assert.NoError(t, err)
   147  
   148  		m := map[string]interface{}{
   149  			"bytes.decimal": big.NewRat(1734, 5),
   150  		}
   151  		err = enc.Encode(m)
   152  
   153  		assert.NoError(t, err)
   154  		assert.Equal(t, []byte{0x2, 0x22, 0x65, 0xea, 0x55, 0xc, 0x11, 0x8, 0xf7, 0xc3, 0xb8, 0xec, 0x53, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0}, buf.Bytes())
   155  	})
   156  }
   157  
   158  func TestEncoder_UnionMapInvalidType(t *testing.T) {
   159  	defer ConfigTeardown()
   160  
   161  	schema := `["null", "string"]`
   162  	buf := bytes.NewBuffer([]byte{})
   163  	enc, err := avro.NewEncoder(schema, buf)
   164  	assert.NoError(t, err)
   165  
   166  	err = enc.Encode(map[string]interface{}{"long": 27})
   167  
   168  	assert.Error(t, err)
   169  }
   170  
   171  func TestEncoder_UnionMapInvalidMap(t *testing.T) {
   172  	defer ConfigTeardown()
   173  
   174  	schema := `["null", "string"]`
   175  	buf := bytes.NewBuffer([]byte{})
   176  	enc, err := avro.NewEncoder(schema, buf)
   177  	assert.NoError(t, err)
   178  
   179  	err = enc.Encode(map[string]string{})
   180  
   181  	assert.Error(t, err)
   182  }
   183  
   184  func TestEncoder_UnionPtr(t *testing.T) {
   185  	defer ConfigTeardown()
   186  
   187  	schema := `["null", "string"]`
   188  	buf := bytes.NewBuffer([]byte{})
   189  	enc, err := avro.NewEncoder(schema, buf)
   190  	assert.NoError(t, err)
   191  
   192  	str := "foo"
   193  	err = enc.Encode(&str)
   194  
   195  	assert.NoError(t, err)
   196  	assert.Equal(t, []byte{0x02, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes())
   197  }
   198  
   199  func TestEncoder_UnionPtrReversed(t *testing.T) {
   200  	defer ConfigTeardown()
   201  
   202  	schema := `["string", "null"]`
   203  	buf := bytes.NewBuffer([]byte{})
   204  	enc, err := avro.NewEncoder(schema, buf)
   205  	assert.NoError(t, err)
   206  
   207  	str := "foo"
   208  	err = enc.Encode(&str)
   209  
   210  	assert.NoError(t, err)
   211  	assert.Equal(t, []byte{0x00, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes())
   212  }
   213  
   214  func TestEncoder_UnionPtrNull(t *testing.T) {
   215  	defer ConfigTeardown()
   216  
   217  	schema := `["null", "string"]`
   218  	buf := bytes.NewBuffer([]byte{})
   219  	enc, err := avro.NewEncoder(schema, buf)
   220  	assert.NoError(t, err)
   221  
   222  	var str *string
   223  	err = enc.Encode(str)
   224  
   225  	assert.NoError(t, err)
   226  	assert.Equal(t, []byte{0x00}, buf.Bytes())
   227  }
   228  
   229  func TestEncoder_UnionPtrReversedNull(t *testing.T) {
   230  	defer ConfigTeardown()
   231  
   232  	schema := `["string", "null"]`
   233  	buf := bytes.NewBuffer([]byte{})
   234  	enc, err := avro.NewEncoder(schema, buf)
   235  	assert.NoError(t, err)
   236  
   237  	var str *string
   238  	err = enc.Encode(str)
   239  
   240  	assert.NoError(t, err)
   241  	assert.Equal(t, []byte{0x02}, buf.Bytes())
   242  }
   243  
   244  func TestEncoder_UnionPtrNotNullable(t *testing.T) {
   245  	defer ConfigTeardown()
   246  
   247  	schema := `["null", "string", "int"]`
   248  	buf := bytes.NewBuffer([]byte{})
   249  	enc, err := avro.NewEncoder(schema, buf)
   250  	assert.NoError(t, err)
   251  
   252  	str := "test"
   253  	err = enc.Encode(&str)
   254  
   255  	assert.Error(t, err)
   256  }
   257  
   258  func TestEncoder_UnionInterface(t *testing.T) {
   259  	defer ConfigTeardown()
   260  
   261  	schema := `["int", "string"]`
   262  	buf := bytes.NewBuffer([]byte{})
   263  	enc, err := avro.NewEncoder(schema, buf)
   264  	assert.NoError(t, err)
   265  
   266  	var val interface{} = "foo"
   267  	err = enc.Encode(val)
   268  
   269  	assert.NoError(t, err)
   270  	assert.Equal(t, []byte{0x02, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes())
   271  }
   272  
   273  func TestEncoder_UnionInterfaceRecord(t *testing.T) {
   274  	defer ConfigTeardown()
   275  
   276  	avro.Register("test", &TestRecord{})
   277  
   278  	schema := `["int", {"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}]`
   279  	buf := bytes.NewBuffer([]byte{})
   280  	enc, err := avro.NewEncoder(schema, buf)
   281  	assert.NoError(t, err)
   282  
   283  	var val interface{} = &TestRecord{A: 27, B: "foo"}
   284  	err = enc.Encode(val)
   285  
   286  	assert.NoError(t, err)
   287  	assert.Equal(t, []byte{0x02, 0x36, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes())
   288  }
   289  
   290  func TestEncoder_UnionInterfaceRecordNonPtr(t *testing.T) {
   291  	defer ConfigTeardown()
   292  
   293  	avro.Register("test", TestRecord{})
   294  
   295  	schema := `["int", {"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}]`
   296  	buf := bytes.NewBuffer([]byte{})
   297  	enc, err := avro.NewEncoder(schema, buf)
   298  	assert.NoError(t, err)
   299  
   300  	var val interface{} = TestRecord{A: 27, B: "foo"}
   301  	err = enc.Encode(val)
   302  
   303  	assert.NoError(t, err)
   304  	assert.Equal(t, []byte{0x02, 0x36, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes())
   305  }
   306  
   307  func TestEncoder_UnionInterfaceMap(t *testing.T) {
   308  	defer ConfigTeardown()
   309  
   310  	avro.Register("map:int", map[string]int{})
   311  
   312  	schema := `["int", {"type": "map", "values": "int"}]`
   313  	buf := bytes.NewBuffer([]byte{})
   314  	enc, err := avro.NewEncoder(schema, buf)
   315  	assert.NoError(t, err)
   316  
   317  	var val interface{} = map[string]int{"foo": 27}
   318  	err = enc.Encode(val)
   319  
   320  	assert.NoError(t, err)
   321  	assert.Equal(t, []byte{0x02, 0x01, 0x0a, 0x06, 0x66, 0x6f, 0x6f, 0x36, 0x00}, buf.Bytes())
   322  }
   323  
   324  func TestEncoder_UnionInterfaceInMapWithBool(t *testing.T) {
   325  	defer ConfigTeardown()
   326  
   327  	schema := `{"type":"map", "values": ["null", "boolean"]}`
   328  	buf := bytes.NewBuffer([]byte{})
   329  	enc, err := avro.NewEncoder(schema, buf)
   330  	assert.NoError(t, err)
   331  
   332  	err = enc.Encode(map[string]interface{}{"foo": true})
   333  
   334  	assert.NoError(t, err)
   335  	assert.Equal(t, []byte{0x01, 0x0c, 0x06, 0x66, 0x6F, 0x6F, 0x02, 0x01, 0x00}, buf.Bytes())
   336  }
   337  
   338  func TestEncoder_UnionInterfaceArray(t *testing.T) {
   339  	defer ConfigTeardown()
   340  
   341  	avro.Register("array:int", []int{})
   342  
   343  	schema := `["int", {"type": "array", "items": "int"}]`
   344  	buf := bytes.NewBuffer([]byte{})
   345  	enc, err := avro.NewEncoder(schema, buf)
   346  	assert.NoError(t, err)
   347  
   348  	var val interface{} = []int{27}
   349  	err = enc.Encode(val)
   350  
   351  	assert.NoError(t, err)
   352  	assert.Equal(t, []byte{0x02, 0x01, 0x02, 0x36, 0x00}, buf.Bytes())
   353  }
   354  
   355  func TestEncoder_UnionInterfaceNull(t *testing.T) {
   356  	defer ConfigTeardown()
   357  
   358  	schema := `{"type": "record", "name": "test", "fields" : [{"name": "a", "type": ["null", "string", "int"]}]}`
   359  	buf := bytes.NewBuffer([]byte{})
   360  	enc, err := avro.NewEncoder(schema, buf)
   361  	assert.NoError(t, err)
   362  
   363  	err = enc.Encode(&TestUnion{A: nil})
   364  
   365  	assert.NoError(t, err)
   366  	assert.Equal(t, []byte{0x00}, buf.Bytes())
   367  }
   368  
   369  func TestEncoder_UnionInterfaceNamed(t *testing.T) {
   370  	defer ConfigTeardown()
   371  
   372  	avro.Register("test", "")
   373  
   374  	schema := `["null", {"type":"enum", "name": "test", "symbols": ["A", "B"]}]`
   375  	buf := bytes.NewBuffer([]byte{})
   376  	enc, err := avro.NewEncoder(schema, buf)
   377  	assert.NoError(t, err)
   378  
   379  	var val interface{} = "B"
   380  	err = enc.Encode(val)
   381  
   382  	assert.NoError(t, err)
   383  	assert.Equal(t, []byte{0x02, 0x02}, buf.Bytes())
   384  }
   385  
   386  func TestEncoder_UnionInterfaceWithTime(t *testing.T) {
   387  	defer ConfigTeardown()
   388  
   389  	schema := `["null", {"type": "long", "logicalType": "timestamp-micros"}]`
   390  	buf := bytes.NewBuffer([]byte{})
   391  	enc, err := avro.NewEncoder(schema, buf)
   392  	assert.NoError(t, err)
   393  
   394  	var val interface{} = time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC)
   395  	err = enc.Encode(val)
   396  
   397  	assert.NoError(t, err)
   398  	assert.Equal(t, []byte{0x02, 0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05}, buf.Bytes())
   399  }
   400  
   401  func TestEncoder_UnionInterfaceWithDuration(t *testing.T) {
   402  	defer ConfigTeardown()
   403  
   404  	schema := `["null", {"type": "int", "logicalType": "time-millis"}]`
   405  	buf := bytes.NewBuffer([]byte{})
   406  	enc, err := avro.NewEncoder(schema, buf)
   407  	assert.NoError(t, err)
   408  
   409  	var val interface{} = 123456789 * time.Millisecond
   410  	err = enc.Encode(val)
   411  
   412  	assert.NoError(t, err)
   413  	assert.Equal(t, []byte{0x02, 0xAA, 0xB4, 0xDE, 0x75}, buf.Bytes())
   414  }
   415  
   416  func TestEncoder_UnionInterfaceWithDecimal(t *testing.T) {
   417  	defer ConfigTeardown()
   418  
   419  	t.Run("low scale", func(t *testing.T) {
   420  		schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}]`
   421  		buf := bytes.NewBuffer([]byte{})
   422  		enc, err := avro.NewEncoder(schema, buf)
   423  		assert.NoError(t, err)
   424  
   425  		var val interface{} = big.NewRat(1734, 5)
   426  		err = enc.Encode(val)
   427  
   428  		assert.NoError(t, err)
   429  		assert.Equal(t, []byte{0x02, 0x6, 0x00, 0x87, 0x78}, buf.Bytes())
   430  	})
   431  
   432  	t.Run("high scale", func(t *testing.T) {
   433  		schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 77, "scale": 38}]`
   434  		buf := bytes.NewBuffer([]byte{})
   435  		enc, err := avro.NewEncoder(schema, buf)
   436  		assert.NoError(t, err)
   437  
   438  		var val interface{} = big.NewRat(1734, 5)
   439  		err = enc.Encode(val)
   440  
   441  		assert.NoError(t, err)
   442  		assert.Equal(t, []byte{0x2, 0x22, 0x65, 0xea, 0x55, 0xc, 0x11, 0x8, 0xf7, 0xc3, 0xb8, 0xec, 0x53, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0}, buf.Bytes())
   443  	})
   444  
   445  }
   446  
   447  func TestEncoder_UnionInterfaceUnregisteredType(t *testing.T) {
   448  	defer ConfigTeardown()
   449  
   450  	schema := `["int", {"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}]`
   451  	buf := bytes.NewBuffer([]byte{})
   452  	enc, err := avro.NewEncoder(schema, buf)
   453  	assert.NoError(t, err)
   454  
   455  	var val interface{} = &TestRecord{}
   456  	err = enc.Encode(val)
   457  
   458  	assert.Error(t, err)
   459  }
   460  
   461  func TestEncoder_UnionInterfaceNotInSchema(t *testing.T) {
   462  	defer ConfigTeardown()
   463  
   464  	avro.Register("test", &TestRecord{})
   465  
   466  	schema := `["int", "string"]`
   467  	buf := bytes.NewBuffer([]byte{})
   468  	enc, err := avro.NewEncoder(schema, buf)
   469  	assert.NoError(t, err)
   470  
   471  	var val interface{} = &TestRecord{}
   472  	err = enc.Encode(val)
   473  
   474  	assert.Error(t, err)
   475  }