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

     1  package avro_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/hamba/avro"
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  func TestParse_InvalidType(t *testing.T) {
    11  	schemas := []string{
    12  		`123`,
    13  		`{"type": 123}`,
    14  	}
    15  
    16  	for _, schm := range schemas {
    17  		_, err := avro.Parse(schm)
    18  
    19  		assert.Error(t, err)
    20  	}
    21  }
    22  
    23  func TestMustParse(t *testing.T) {
    24  	s := avro.MustParse("null")
    25  
    26  	assert.Equal(t, avro.Null, s.Type())
    27  }
    28  
    29  func TestMustParse_PanicsOnError(t *testing.T) {
    30  	assert.Panics(t, func() {
    31  		avro.MustParse("123")
    32  	})
    33  }
    34  
    35  func TestParseFiles(t *testing.T) {
    36  	s, err := avro.ParseFiles("testdata/schema.avsc")
    37  
    38  	assert.NoError(t, err)
    39  	assert.Equal(t, avro.String, s.Type())
    40  }
    41  
    42  func TestParseFiles_FileDoesntExist(t *testing.T) {
    43  	_, err := avro.ParseFiles("test.something")
    44  
    45  	assert.Error(t, err)
    46  }
    47  
    48  func TestParseFiles_InvalidSchema(t *testing.T) {
    49  	_, err := avro.ParseFiles("testdata/bad-schema.avsc")
    50  
    51  	assert.Error(t, err)
    52  }
    53  
    54  func TestNullSchema(t *testing.T) {
    55  	schemas := []string{
    56  		`null`,
    57  		`{"type":"null"}`,
    58  	}
    59  
    60  	for _, schm := range schemas {
    61  		schema, err := avro.Parse(schm)
    62  
    63  		assert.NoError(t, err)
    64  		assert.Equal(t, avro.Null, schema.Type())
    65  		want := [32]byte{0xf0, 0x72, 0xcb, 0xec, 0x3b, 0xf8, 0x84, 0x18, 0x71, 0xd4, 0x28, 0x42, 0x30, 0xc5, 0xe9, 0x83, 0xdc, 0x21, 0x1a, 0x56, 0x83, 0x7a, 0xed, 0x86, 0x24, 0x87, 0x14, 0x8f, 0x94, 0x7d, 0x1a, 0x1f}
    66  		assert.Equal(t, want, schema.Fingerprint())
    67  	}
    68  }
    69  
    70  func TestPrimitiveSchema(t *testing.T) {
    71  	tests := []struct {
    72  		schema          string
    73  		want            avro.Type
    74  		wantFingerprint [32]byte
    75  	}{
    76  		{
    77  			schema:          "string",
    78  			want:            avro.String,
    79  			wantFingerprint: [32]byte{0xe9, 0xe5, 0xc1, 0xc9, 0xe4, 0xf6, 0x27, 0x73, 0x39, 0xd1, 0xbc, 0xde, 0x7, 0x33, 0xa5, 0x9b, 0xd4, 0x2f, 0x87, 0x31, 0xf4, 0x49, 0xda, 0x6d, 0xc1, 0x30, 0x10, 0xa9, 0x16, 0x93, 0xd, 0x48},
    80  		},
    81  		{
    82  			schema:          `{"type":"string"}`,
    83  			want:            avro.String,
    84  			wantFingerprint: [32]byte{0xe9, 0xe5, 0xc1, 0xc9, 0xe4, 0xf6, 0x27, 0x73, 0x39, 0xd1, 0xbc, 0xde, 0x7, 0x33, 0xa5, 0x9b, 0xd4, 0x2f, 0x87, 0x31, 0xf4, 0x49, 0xda, 0x6d, 0xc1, 0x30, 0x10, 0xa9, 0x16, 0x93, 0xd, 0x48},
    85  		},
    86  		{
    87  			schema:          "bytes",
    88  			want:            avro.Bytes,
    89  			wantFingerprint: [32]byte{0x9a, 0xe5, 0x7, 0xa9, 0xdd, 0x39, 0xee, 0x5b, 0x7c, 0x7e, 0x28, 0x5d, 0xa2, 0xc0, 0x84, 0x65, 0x21, 0xc8, 0xae, 0x8d, 0x80, 0xfe, 0xea, 0xe5, 0x50, 0x4e, 0xc, 0x98, 0x1d, 0x53, 0xf5, 0xfa},
    90  		},
    91  		{
    92  			schema:          `{"type":"bytes"}`,
    93  			want:            avro.Bytes,
    94  			wantFingerprint: [32]byte{0x9a, 0xe5, 0x7, 0xa9, 0xdd, 0x39, 0xee, 0x5b, 0x7c, 0x7e, 0x28, 0x5d, 0xa2, 0xc0, 0x84, 0x65, 0x21, 0xc8, 0xae, 0x8d, 0x80, 0xfe, 0xea, 0xe5, 0x50, 0x4e, 0xc, 0x98, 0x1d, 0x53, 0xf5, 0xfa},
    95  		},
    96  		{
    97  			schema:          "int",
    98  			want:            avro.Int,
    99  			wantFingerprint: [32]byte{0x3f, 0x2b, 0x87, 0xa9, 0xfe, 0x7c, 0xc9, 0xb1, 0x38, 0x35, 0x59, 0x8c, 0x39, 0x81, 0xcd, 0x45, 0xe3, 0xe3, 0x55, 0x30, 0x9e, 0x50, 0x90, 0xaa, 0x9, 0x33, 0xd7, 0xbe, 0xcb, 0x6f, 0xba, 0x45},
   100  		},
   101  		{
   102  			schema:          `{"type":"int"}`,
   103  			want:            avro.Int,
   104  			wantFingerprint: [32]byte{0x3f, 0x2b, 0x87, 0xa9, 0xfe, 0x7c, 0xc9, 0xb1, 0x38, 0x35, 0x59, 0x8c, 0x39, 0x81, 0xcd, 0x45, 0xe3, 0xe3, 0x55, 0x30, 0x9e, 0x50, 0x90, 0xaa, 0x9, 0x33, 0xd7, 0xbe, 0xcb, 0x6f, 0xba, 0x45},
   105  		},
   106  		{
   107  			schema:          "long",
   108  			want:            avro.Long,
   109  			wantFingerprint: [32]byte{0xc3, 0x2c, 0x49, 0x7d, 0xf6, 0x73, 0xc, 0x97, 0xfa, 0x7, 0x36, 0x2a, 0xa5, 0x2, 0x3f, 0x37, 0xd4, 0x9a, 0x2, 0x7e, 0xc4, 0x52, 0x36, 0x7, 0x78, 0x11, 0x4c, 0xf4, 0x27, 0x96, 0x5a, 0xdd},
   110  		},
   111  		{
   112  			schema:          `{"type":"long"}`,
   113  			want:            avro.Long,
   114  			wantFingerprint: [32]byte{0xc3, 0x2c, 0x49, 0x7d, 0xf6, 0x73, 0xc, 0x97, 0xfa, 0x7, 0x36, 0x2a, 0xa5, 0x2, 0x3f, 0x37, 0xd4, 0x9a, 0x2, 0x7e, 0xc4, 0x52, 0x36, 0x7, 0x78, 0x11, 0x4c, 0xf4, 0x27, 0x96, 0x5a, 0xdd},
   115  		},
   116  		{
   117  			schema:          "float",
   118  			want:            avro.Float,
   119  			wantFingerprint: [32]byte{0x1e, 0x71, 0xf9, 0xec, 0x5, 0x1d, 0x66, 0x3f, 0x56, 0xb0, 0xd8, 0xe1, 0xfc, 0x84, 0xd7, 0x1a, 0xa5, 0x6c, 0xcf, 0xe9, 0xfa, 0x93, 0xaa, 0x20, 0xd1, 0x5, 0x47, 0xa7, 0xab, 0xeb, 0x5c, 0xc0},
   120  		},
   121  		{
   122  			schema:          `{"type":"float"}`,
   123  			want:            avro.Float,
   124  			wantFingerprint: [32]byte{0x1e, 0x71, 0xf9, 0xec, 0x5, 0x1d, 0x66, 0x3f, 0x56, 0xb0, 0xd8, 0xe1, 0xfc, 0x84, 0xd7, 0x1a, 0xa5, 0x6c, 0xcf, 0xe9, 0xfa, 0x93, 0xaa, 0x20, 0xd1, 0x5, 0x47, 0xa7, 0xab, 0xeb, 0x5c, 0xc0},
   125  		},
   126  		{
   127  			schema:          "double",
   128  			want:            avro.Double,
   129  			wantFingerprint: [32]byte{0x73, 0xa, 0x9a, 0x8c, 0x61, 0x16, 0x81, 0xd7, 0xee, 0xf4, 0x42, 0xe0, 0x3c, 0x16, 0xc7, 0xd, 0x13, 0xbc, 0xa3, 0xeb, 0x8b, 0x97, 0x7b, 0xb4, 0x3, 0xea, 0xff, 0x52, 0x17, 0x6a, 0xf2, 0x54},
   130  		},
   131  		{
   132  			schema:          `{"type":"double"}`,
   133  			want:            avro.Double,
   134  			wantFingerprint: [32]byte{0x73, 0xa, 0x9a, 0x8c, 0x61, 0x16, 0x81, 0xd7, 0xee, 0xf4, 0x42, 0xe0, 0x3c, 0x16, 0xc7, 0xd, 0x13, 0xbc, 0xa3, 0xeb, 0x8b, 0x97, 0x7b, 0xb4, 0x3, 0xea, 0xff, 0x52, 0x17, 0x6a, 0xf2, 0x54},
   135  		},
   136  		{
   137  			schema:          "boolean",
   138  			want:            avro.Boolean,
   139  			wantFingerprint: [32]byte{0xa5, 0xb0, 0x31, 0xab, 0x62, 0xbc, 0x41, 0x6d, 0x72, 0xc, 0x4, 0x10, 0xd8, 0x2, 0xea, 0x46, 0xb9, 0x10, 0xc4, 0xfb, 0xe8, 0x5c, 0x50, 0xa9, 0x46, 0xcc, 0xc6, 0x58, 0xb7, 0x4e, 0x67, 0x7e},
   140  		},
   141  		{
   142  			schema:          `{"type":"boolean"}`,
   143  			want:            avro.Boolean,
   144  			wantFingerprint: [32]byte{0xa5, 0xb0, 0x31, 0xab, 0x62, 0xbc, 0x41, 0x6d, 0x72, 0xc, 0x4, 0x10, 0xd8, 0x2, 0xea, 0x46, 0xb9, 0x10, 0xc4, 0xfb, 0xe8, 0x5c, 0x50, 0xa9, 0x46, 0xcc, 0xc6, 0x58, 0xb7, 0x4e, 0x67, 0x7e},
   145  		},
   146  	}
   147  
   148  	for _, tt := range tests {
   149  		t.Run(tt.schema, func(t *testing.T) {
   150  			s, err := avro.Parse(tt.schema)
   151  
   152  			assert.NoError(t, err)
   153  			assert.Equal(t, tt.want, s.Type())
   154  			assert.Equal(t, tt.wantFingerprint, s.Fingerprint())
   155  		})
   156  	}
   157  }
   158  
   159  func TestPrimitiveSchema_HandlesProps(t *testing.T) {
   160  	schm := `
   161  {
   162     "type": "string",
   163     "foo": "bar",
   164     "baz": 1
   165  }
   166  `
   167  
   168  	s, err := avro.Parse(schm)
   169  
   170  	assert.NoError(t, err)
   171  	assert.Equal(t, avro.String, s.Type())
   172  	assert.Equal(t, "bar", s.(*avro.PrimitiveSchema).Prop("foo"))
   173  	assert.Equal(t, float64(1), s.(*avro.PrimitiveSchema).Prop("baz"))
   174  }
   175  
   176  func TestRecordSchema(t *testing.T) {
   177  	tests := []struct {
   178  		name    string
   179  		schema  string
   180  		wantErr bool
   181  	}{
   182  		{
   183  			name:    "Valid",
   184  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "doc": "docs", "fields":[{"name": "field", "type": "int"}]}`,
   185  			wantErr: false,
   186  		},
   187  		{
   188  			name:    "Invalid Name First Char",
   189  			schema:  `{"type":"record", "name":"0test", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
   190  			wantErr: true,
   191  		},
   192  		{
   193  			name:    "Invalid Name Other Char",
   194  			schema:  `{"type":"record", "name":"test+", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
   195  			wantErr: true,
   196  		},
   197  		{
   198  			name:    "Empty Name",
   199  			schema:  `{"type":"record", "name":"", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
   200  			wantErr: true,
   201  		},
   202  		{
   203  			name:    "No Name",
   204  			schema:  `{"type":"record", "namespace": "org.hamba.avro", "fields":[{"name": "intField", "type": "int"}]}`,
   205  			wantErr: true,
   206  		},
   207  		{
   208  			name:    "Invalid Namespace",
   209  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro+", "fields":[{"name": "field", "type": "int"}]}`,
   210  			wantErr: true,
   211  		},
   212  		{
   213  			name:    "Empty Namespace",
   214  			schema:  `{"type":"record", "name":"test", "namespace": "", "fields":[{"name": "intField", "type": "int"}]}`,
   215  			wantErr: true,
   216  		},
   217  		{
   218  			name:    "No Fields",
   219  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro"}`,
   220  			wantErr: true,
   221  		},
   222  		{
   223  			name:    "Invalid Field Type",
   224  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":["test"]}`,
   225  			wantErr: true,
   226  		},
   227  		{
   228  			name:    "No Field Name",
   229  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"type": "int"}]}`,
   230  			wantErr: true,
   231  		},
   232  		{
   233  			name:    "Invalid Field Name",
   234  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "field+", "type": "int"}]}`,
   235  			wantErr: true,
   236  		},
   237  		{
   238  			name:    "No Field Type",
   239  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "field"}]}`,
   240  			wantErr: true,
   241  		},
   242  		{
   243  			name:    "Invalid Field Type",
   244  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "blah"}]}`,
   245  			wantErr: true,
   246  		},
   247  	}
   248  
   249  	for _, tt := range tests {
   250  		t.Run(tt.name, func(t *testing.T) {
   251  			s, err := avro.Parse(tt.schema)
   252  
   253  			if tt.wantErr {
   254  				assert.Error(t, err)
   255  				return
   256  			}
   257  
   258  			assert.NoError(t, err)
   259  			assert.Equal(t, avro.Record, s.Type())
   260  		})
   261  	}
   262  }
   263  
   264  func TestErrorRecordSchema(t *testing.T) {
   265  	tests := []struct {
   266  		name    string
   267  		schema  string
   268  		wantErr bool
   269  	}{
   270  		{
   271  			name:    "Valid",
   272  			schema:  `{"type":"error", "name":"test", "namespace": "org.hamba.avro", "doc": "docs", "fields":[{"name": "field", "type": "int"}]}`,
   273  			wantErr: false,
   274  		},
   275  		{
   276  			name:    "Invalid Name First Char",
   277  			schema:  `{"type":"error", "name":"0test", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
   278  			wantErr: true,
   279  		},
   280  		{
   281  			name:    "Invalid Name Other Char",
   282  			schema:  `{"type":"error", "name":"test+", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
   283  			wantErr: true,
   284  		},
   285  		{
   286  			name:    "Empty Name",
   287  			schema:  `{"type":"error", "name":"", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
   288  			wantErr: true,
   289  		},
   290  		{
   291  			name:    "No Name",
   292  			schema:  `{"type":"error", "namespace": "org.hamba.avro", "fields":[{"name": "intField", "type": "int"}]}`,
   293  			wantErr: true,
   294  		},
   295  		{
   296  			name:    "Invalid Namespace",
   297  			schema:  `{"type":"error", "name":"test", "namespace": "org.hamba.avro+", "fields":[{"name": "field", "type": "int"}]}`,
   298  			wantErr: true,
   299  		},
   300  		{
   301  			name:    "Empty Namespace",
   302  			schema:  `{"type":"error", "name":"test", "namespace": "", "fields":[{"name": "intField", "type": "int"}]}`,
   303  			wantErr: true,
   304  		},
   305  	}
   306  
   307  	for _, tt := range tests {
   308  		t.Run(tt.name, func(t *testing.T) {
   309  
   310  			s, err := avro.Parse(tt.schema)
   311  
   312  			if tt.wantErr {
   313  				assert.Error(t, err)
   314  				return
   315  			}
   316  
   317  			assert.NoError(t, err)
   318  			assert.Equal(t, avro.Record, s.Type())
   319  			recSchema := s.(*avro.RecordSchema)
   320  			assert.True(t, recSchema.IsError())
   321  		})
   322  	}
   323  }
   324  
   325  func TestRecordSchema_ValidatesDefault(t *testing.T) {
   326  	tests := []struct {
   327  		name    string
   328  		schema  string
   329  		wantErr bool
   330  	}{
   331  		{
   332  			name:    "String",
   333  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "string", "default": "test"}]}`,
   334  			wantErr: false,
   335  		},
   336  		{
   337  			name:    "Int",
   338  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "int", "default": 1}]}`,
   339  			wantErr: false,
   340  		},
   341  		{
   342  			name:    "Long",
   343  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "long", "default": 1}]}`,
   344  			wantErr: false,
   345  		},
   346  		{
   347  			name:    "Float",
   348  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "float", "default": 1}]}`,
   349  			wantErr: false,
   350  		},
   351  		{
   352  			name:    "Double",
   353  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": "double", "default": 1}]}`,
   354  			wantErr: false,
   355  		},
   356  		{
   357  			name:    "Array",
   358  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"array", "items": "int"}, "default": [1,2]}]}`,
   359  			wantErr: false,
   360  		},
   361  		{
   362  			name:    "Array Not Array",
   363  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"array", "items": "int"}, "default": "test"}]}`,
   364  			wantErr: true,
   365  		},
   366  		{
   367  			name:    "Array Invalid Type",
   368  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"array", "items": "int"}, "default": ["test"]}]}`,
   369  			wantErr: true,
   370  		},
   371  		{
   372  			name:    "Map",
   373  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"map", "values": "int"}, "default": {"b": 1}}]}`,
   374  			wantErr: false,
   375  		},
   376  		{
   377  			name:    "Map Not Map",
   378  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"map", "values": "int"}, "default": "test"}]}`,
   379  			wantErr: true,
   380  		},
   381  		{
   382  			name:    "Map Invalid Type",
   383  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"map", "values": "int"}, "default": {"b": "test"}}]}`,
   384  			wantErr: true,
   385  		},
   386  		{
   387  			name:    "Union",
   388  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": ["string", "null"]}]}`,
   389  			wantErr: false,
   390  		},
   391  		{
   392  			name:    "Union Default",
   393  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": ["null", "string"], "default": null}]}`,
   394  			wantErr: false,
   395  		},
   396  		{
   397  			name:    "Union Invalid Type",
   398  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": ["null", "string"], "default": "string"}]}`,
   399  			wantErr: true,
   400  		},
   401  		{
   402  			name:    "Record",
   403  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"record", "name": "test2", "fields":[{"name": "b", "type": "int"},{"name": "c", "type": "int", "default": 1}]}, "default": {"b": 1}}]}`,
   404  			wantErr: false,
   405  		},
   406  		{
   407  			name:    "Record Not Map",
   408  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"record", "name": "test2", "fields":[{"name": "b", "type": "int"},{"name": "c", "type": "int", "default": 1}]}, "default": "test"}]}`,
   409  			wantErr: true,
   410  		},
   411  		{
   412  			name:    "Record Invalid Type",
   413  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"record", "name": "test2", "fields":[{"name": "b", "type": "int"},{"name": "c", "type": "int", "default": 1}]}, "default": {"b": "test"}}]}`,
   414  			wantErr: true,
   415  		},
   416  		{
   417  			name:    "Record Invalid Field Type",
   418  			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": {"type":"record", "name": "test2", "fields":[{"name": "b", "type": "int"},{"name": "c", "type": "int", "default": "test"}]}, "default": {"b": 1}}]}`,
   419  			wantErr: true,
   420  		},
   421  	}
   422  
   423  	for _, tt := range tests {
   424  		t.Run(tt.name, func(t *testing.T) {
   425  			_, err := avro.Parse(tt.schema)
   426  
   427  			if tt.wantErr {
   428  				assert.Error(t, err)
   429  				return
   430  			}
   431  
   432  			assert.NoError(t, err)
   433  		})
   434  	}
   435  }
   436  
   437  func TestRecordSchema_HandlesProps(t *testing.T) {
   438  	schm := `
   439  {
   440     "type": "record",
   441     "name": "valid_name",
   442     "namespace": "org.hamba.avro",
   443     "foo": "bar1",
   444     "fields": [
   445         {"name": "intField", "type": "int", "foo": "bar2"}
   446     ]
   447  }
   448  `
   449  
   450  	s, err := avro.Parse(schm)
   451  
   452  	assert.NoError(t, err)
   453  	assert.Equal(t, avro.Record, s.Type())
   454  	assert.Equal(t, "bar1", s.(*avro.RecordSchema).Prop("foo"))
   455  	assert.Equal(t, "bar2", s.(*avro.RecordSchema).Fields()[0].Prop("foo"))
   456  }
   457  
   458  func TestRecordSchema_WithReference(t *testing.T) {
   459  	schm := `
   460  {
   461     "type": "record",
   462     "name": "valid_name",
   463     "namespace": "org.hamba.avro",
   464     "fields": [
   465         {"name": "intField", "type": "int"},
   466         {"name": "Ref", "type": "valid_name"}
   467     ]
   468  }
   469  `
   470  
   471  	s, err := avro.Parse(schm)
   472  
   473  	assert.NoError(t, err)
   474  	assert.Equal(t, avro.Record, s.Type())
   475  	assert.Equal(t, avro.Ref, s.(*avro.RecordSchema).Fields()[1].Type().Type())
   476  	assert.Equal(t, s.Fingerprint(), s.(*avro.RecordSchema).Fields()[1].Type().Fingerprint())
   477  }
   478  
   479  func TestEnumSchema(t *testing.T) {
   480  	tests := []struct {
   481  		name     string
   482  		schema   string
   483  		wantName string
   484  		wantErr  bool
   485  	}{
   486  		{
   487  			name:     "Valid",
   488  			schema:   `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
   489  			wantName: "org.hamba.avro.test",
   490  			wantErr:  false,
   491  		},
   492  		{
   493  			name:    "Invalid Name",
   494  			schema:  `{"type":"enum", "name":"test+", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
   495  			wantErr: true,
   496  		},
   497  		{
   498  			name:    "Empty Name",
   499  			schema:  `{"type":"enum", "name":"", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
   500  			wantErr: true,
   501  		},
   502  		{
   503  			name:    "No Name",
   504  			schema:  `{"type":"enum", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
   505  			wantErr: true,
   506  		},
   507  		{
   508  			name:    "Invalid Namespace",
   509  			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro+", "symbols":["TEST"]}`,
   510  			wantErr: true,
   511  		},
   512  		{
   513  			name:    "Empty Namespace",
   514  			schema:  `{"type":"enum", "name":"test", "namespace": "", "symbols":["TEST"]}`,
   515  			wantErr: true,
   516  		},
   517  		{
   518  			name:    "No Symbols",
   519  			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro"}`,
   520  			wantErr: true,
   521  		},
   522  		{
   523  			name:    "Empty Symbols",
   524  			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":[]}`,
   525  			wantErr: true,
   526  		},
   527  		{
   528  			name:    "Invalid Symbol",
   529  			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST+"]}`,
   530  			wantErr: true,
   531  		},
   532  		{
   533  			name:    "Invalid Symbol Type",
   534  			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":[1]}`,
   535  			wantErr: true,
   536  		},
   537  	}
   538  
   539  	for _, tt := range tests {
   540  		t.Run(tt.name, func(t *testing.T) {
   541  			schema, err := avro.Parse(tt.schema)
   542  
   543  			if tt.wantErr {
   544  				assert.Error(t, err)
   545  				return
   546  			}
   547  
   548  			assert.NoError(t, err)
   549  			assert.Equal(t, avro.Enum, schema.Type())
   550  			named := schema.(avro.NamedSchema)
   551  			assert.Equal(t, tt.wantName, named.FullName())
   552  		})
   553  	}
   554  }
   555  
   556  func TestEnumSchema_HandlesProps(t *testing.T) {
   557  	schm := `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST"], "foo":"bar"}`
   558  
   559  	s, err := avro.Parse(schm)
   560  
   561  	assert.NoError(t, err)
   562  	assert.Equal(t, avro.Enum, s.Type())
   563  	assert.Equal(t, "bar", s.(*avro.EnumSchema).Prop("foo"))
   564  }
   565  
   566  func TestArraySchema(t *testing.T) {
   567  	tests := []struct {
   568  		name    string
   569  		schema  string
   570  		wantErr bool
   571  	}{
   572  		{
   573  			name:    "Valid",
   574  			schema:  `{"type":"array", "items": "int"}`,
   575  			wantErr: false,
   576  		},
   577  		{
   578  			name:    "No Items",
   579  			schema:  `{"type":"array"}`,
   580  			wantErr: true,
   581  		},
   582  		{
   583  			name:    "Invalid Items Type",
   584  			schema:  `{"type":"array", "items": "blah"}`,
   585  			wantErr: true,
   586  		},
   587  	}
   588  
   589  	for _, tt := range tests {
   590  		t.Run(tt.name, func(t *testing.T) {
   591  			s, err := avro.Parse(tt.schema)
   592  
   593  			if tt.wantErr {
   594  				assert.Error(t, err)
   595  				return
   596  			}
   597  
   598  			assert.NoError(t, err)
   599  			assert.Equal(t, avro.Array, s.Type())
   600  		})
   601  	}
   602  }
   603  
   604  func TestArraySchema_HandlesProps(t *testing.T) {
   605  	schm := `{"type":"array", "items": "int", "foo":"bar"}`
   606  
   607  	s, err := avro.Parse(schm)
   608  
   609  	assert.NoError(t, err)
   610  	assert.Equal(t, avro.Array, s.Type())
   611  	assert.Equal(t, "bar", s.(*avro.ArraySchema).Prop("foo"))
   612  }
   613  
   614  func TestMapSchema(t *testing.T) {
   615  	tests := []struct {
   616  		name    string
   617  		schema  string
   618  		wantErr bool
   619  	}{
   620  		{
   621  			name:    "Valid",
   622  			schema:  `{"type":"map", "values": "int"}`,
   623  			wantErr: false,
   624  		},
   625  		{
   626  			name:    "No Values",
   627  			schema:  `{"type":"map"}`,
   628  			wantErr: true,
   629  		},
   630  		{
   631  			name:    "Invalid Values Type",
   632  			schema:  `{"type":"map", "values": "blah"}`,
   633  			wantErr: true,
   634  		},
   635  	}
   636  
   637  	for _, tt := range tests {
   638  		t.Run(tt.name, func(t *testing.T) {
   639  			s, err := avro.Parse(tt.schema)
   640  
   641  			if tt.wantErr {
   642  				assert.Error(t, err)
   643  				return
   644  			}
   645  
   646  			assert.NoError(t, err)
   647  			assert.Equal(t, avro.Map, s.Type())
   648  		})
   649  	}
   650  }
   651  
   652  func TestMapSchema_HandlesProps(t *testing.T) {
   653  	schm := `{"type":"map", "values": "int", "foo":"bar"}`
   654  
   655  	s, err := avro.Parse(schm)
   656  
   657  	assert.NoError(t, err)
   658  	assert.Equal(t, avro.Map, s.Type())
   659  	assert.Equal(t, "bar", s.(*avro.MapSchema).Prop("foo"))
   660  }
   661  
   662  func TestUnionSchema(t *testing.T) {
   663  	tests := []struct {
   664  		name            string
   665  		schema          string
   666  		wantFingerprint [32]byte
   667  		wantErr         bool
   668  	}{
   669  		{
   670  			name:            "Valid Simple",
   671  			schema:          `["null", "int"]`,
   672  			wantFingerprint: [32]byte{0xb4, 0x94, 0x95, 0xc5, 0xb1, 0xc2, 0x6f, 0x4, 0x89, 0x6a, 0x5f, 0x68, 0x65, 0xf, 0xe2, 0xb7, 0x64, 0x23, 0x62, 0xc3, 0x41, 0x98, 0xd6, 0xbc, 0x74, 0x65, 0xa1, 0xd9, 0xf7, 0xe1, 0xaf, 0xce},
   673  			wantErr:         false,
   674  		},
   675  		{
   676  			name:            "Valid Complex",
   677  			schema:          `{"type":["null", "int"]}`,
   678  			wantFingerprint: [32]byte{0xb4, 0x94, 0x95, 0xc5, 0xb1, 0xc2, 0x6f, 0x4, 0x89, 0x6a, 0x5f, 0x68, 0x65, 0xf, 0xe2, 0xb7, 0x64, 0x23, 0x62, 0xc3, 0x41, 0x98, 0xd6, 0xbc, 0x74, 0x65, 0xa1, 0xd9, 0xf7, 0xe1, 0xaf, 0xce},
   679  			wantErr:         false,
   680  		},
   681  		{
   682  			name:            "Dereferences Ref Schemas",
   683  			schema:          `[{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}, {"type":"enum", "name":"test1", "namespace": "org.hamba.avro", "symbols":["TEST"]}, {"type":"record", "name":"test2", "namespace": "org.hamba.avro", "fields":[{"name": "a", "type": ["null","org.hamba.avro.test","org.hamba.avro.test1"]}]}]`,
   684  			wantFingerprint: [32]byte{0xc1, 0x42, 0x87, 0xde, 0x24, 0x3d, 0xee, 0x1d, 0xa5, 0x47, 0xa0, 0x13, 0x9e, 0xb, 0xe0, 0x6, 0xfd, 0xa, 0x76, 0xd9, 0xe8, 0x92, 0x9a, 0xd3, 0x46, 0xf, 0xbd, 0x86, 0x21, 0x72, 0x81, 0x1b},
   685  			wantErr:         false,
   686  		},
   687  		{
   688  			name:    "No Nested Union Type",
   689  			schema:  `["null", ["string"]]`,
   690  			wantErr: true,
   691  		},
   692  		{
   693  			name:    "No Duplicate Types",
   694  			schema:  `["string", "string"]`,
   695  			wantErr: true,
   696  		},
   697  		{
   698  			name:    "No Duplicate Names",
   699  			schema:  `[{"type":"enum", "name":"test", "symbols":["TEST"]}, {"type":"enum", "name":"test", "symbols":["TEST"]}]`,
   700  			wantErr: true,
   701  		},
   702  		{
   703  			name:    "Invalid Type",
   704  			schema:  `["null", "blah"]`,
   705  			wantErr: true,
   706  		},
   707  	}
   708  
   709  	for _, tt := range tests {
   710  		t.Run(tt.name, func(t *testing.T) {
   711  			s, err := avro.Parse(tt.schema)
   712  
   713  			if tt.wantErr {
   714  				assert.Error(t, err)
   715  				return
   716  			}
   717  
   718  			assert.NoError(t, err)
   719  			assert.Equal(t, avro.Union, s.Type())
   720  			assert.Equal(t, tt.wantFingerprint, s.Fingerprint())
   721  		})
   722  	}
   723  }
   724  
   725  func TestUnionSchema_Indices(t *testing.T) {
   726  	tests := []struct {
   727  		name   string
   728  		schema string
   729  		want   [2]int
   730  	}{
   731  		{
   732  			name:   "Null First",
   733  			schema: `["null", "string"]`,
   734  			want:   [2]int{0, 1},
   735  		},
   736  		{
   737  			name:   "Null Second",
   738  			schema: `["string", "null"]`,
   739  			want:   [2]int{1, 0},
   740  		},
   741  		{
   742  			name:   "Not Nullable",
   743  			schema: `["null", "string", "int"]`,
   744  			want:   [2]int{0, 0},
   745  		},
   746  	}
   747  
   748  	for _, tt := range tests {
   749  		t.Run(tt.name, func(t *testing.T) {
   750  			s, err := avro.Parse(tt.schema)
   751  
   752  			assert.NoError(t, err)
   753  			null, typ := s.(*avro.UnionSchema).Indices()
   754  			assert.Equal(t, tt.want[0], null)
   755  			assert.Equal(t, tt.want[1], typ)
   756  		})
   757  	}
   758  }
   759  
   760  func TestFixedSchema(t *testing.T) {
   761  	tests := []struct {
   762  		name            string
   763  		schema          string
   764  		wantName        string
   765  		wantFingerprint [32]byte
   766  		wantErr         bool
   767  	}{
   768  		{
   769  			name:            "Valid",
   770  			schema:          `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}`,
   771  			wantName:        "org.hamba.avro.test",
   772  			wantFingerprint: [32]uint8{0x8c, 0x9e, 0xcb, 0x4, 0x83, 0x2f, 0x3b, 0xa7, 0x58, 0x85, 0x9, 0x99, 0x41, 0xe, 0xbf, 0xd4, 0x7, 0xc7, 0x87, 0x4f, 0x8a, 0x12, 0xf4, 0xd0, 0x7f, 0x45, 0xdd, 0xaa, 0x10, 0x6b, 0x2f, 0xb3},
   773  			wantErr:         false,
   774  		},
   775  		{
   776  			name:    "Invalid Name",
   777  			schema:  `{"type":"fixed", "name":"test+", "namespace": "org.hamba.avro", "size": 12}`,
   778  			wantErr: true,
   779  		},
   780  		{
   781  			name:    "Empty Name",
   782  			schema:  `{"type":"fixed", "name":"", "namespace": "org.hamba.avro", "size": 12}`,
   783  			wantErr: true,
   784  		},
   785  		{
   786  			name:    "No Name",
   787  			schema:  `{"type":"fixed", "namespace": "org.hamba.avro", "size": 12}`,
   788  			wantErr: true,
   789  		},
   790  		{
   791  			name:    "Invalid Namespace",
   792  			schema:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro+", "size": 12}`,
   793  			wantErr: true,
   794  		},
   795  		{
   796  			name:    "Empty Namespace",
   797  			schema:  `{"type":"fixed", "name":"test", "namespace": "", "size": 12}`,
   798  			wantErr: true,
   799  		},
   800  		{
   801  			name:    "No Size",
   802  			schema:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro"}`,
   803  			wantErr: true,
   804  		},
   805  		{
   806  			name:    "Invalid Size Type",
   807  			schema:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": "test"}`,
   808  			wantErr: true,
   809  		},
   810  	}
   811  
   812  	for _, tt := range tests {
   813  		t.Run(tt.name, func(t *testing.T) {
   814  			schema, err := avro.Parse(tt.schema)
   815  
   816  			if tt.wantErr {
   817  				assert.Error(t, err)
   818  				return
   819  			}
   820  
   821  			assert.NoError(t, err)
   822  			assert.Equal(t, avro.Fixed, schema.Type())
   823  			named := schema.(avro.NamedSchema)
   824  			assert.Equal(t, tt.wantName, named.FullName())
   825  			assert.Equal(t, tt.wantFingerprint, named.Fingerprint())
   826  		})
   827  	}
   828  }
   829  
   830  func TestFixedSchema_HandlesProps(t *testing.T) {
   831  	schm := `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12, "foo":"bar"}`
   832  
   833  	s, err := avro.Parse(schm)
   834  
   835  	assert.NoError(t, err)
   836  	assert.Equal(t, avro.Fixed, s.Type())
   837  	assert.Equal(t, "bar", s.(*avro.FixedSchema).Prop("foo"))
   838  }
   839  
   840  func TestSchema_LogicalTypes(t *testing.T) {
   841  	tests := []struct {
   842  		name            string
   843  		schema          string
   844  		wantType        avro.Type
   845  		wantLogical     bool
   846  		wantLogicalType avro.LogicalType
   847  		assertFn        func(t *testing.T, ls avro.LogicalSchema)
   848  	}{
   849  		{
   850  			name:        "Invalid",
   851  			schema:      `{"type": "int", "logicalType": "test"}`,
   852  			wantType:    avro.Int,
   853  			wantLogical: false,
   854  		},
   855  		{
   856  			name:            "Date",
   857  			schema:          `{"type": "int", "logicalType": "date"}`,
   858  			wantType:        avro.Int,
   859  			wantLogical:     true,
   860  			wantLogicalType: avro.Date,
   861  		},
   862  		{
   863  			name:            "Time Millis",
   864  			schema:          `{"type": "int", "logicalType": "time-millis"}`,
   865  			wantType:        avro.Int,
   866  			wantLogical:     true,
   867  			wantLogicalType: avro.TimeMillis,
   868  		},
   869  		{
   870  			name:            "Time Micros",
   871  			schema:          `{"type": "long", "logicalType": "time-micros"}`,
   872  			wantType:        avro.Long,
   873  			wantLogical:     true,
   874  			wantLogicalType: avro.TimeMicros,
   875  		},
   876  		{
   877  			name:            "Timestamp Millis",
   878  			schema:          `{"type": "long", "logicalType": "timestamp-millis"}`,
   879  			wantType:        avro.Long,
   880  			wantLogical:     true,
   881  			wantLogicalType: avro.TimestampMillis,
   882  		},
   883  		{
   884  			name:            "Timestamp Micros",
   885  			schema:          `{"type": "long", "logicalType": "timestamp-micros"}`,
   886  			wantType:        avro.Long,
   887  			wantLogical:     true,
   888  			wantLogicalType: avro.TimestampMicros,
   889  		},
   890  		{
   891  			name:            "UUID",
   892  			schema:          `{"type": "string", "logicalType": "uuid"}`,
   893  			wantType:        avro.String,
   894  			wantLogical:     true,
   895  			wantLogicalType: avro.UUID,
   896  		},
   897  		{
   898  			name:            "Duration",
   899  			schema:          `{"type": "fixed", "name":"test", "size": 12, "logicalType": "duration"}`,
   900  			wantType:        avro.Fixed,
   901  			wantLogical:     true,
   902  			wantLogicalType: avro.Duration,
   903  		},
   904  		{
   905  			name:        "Invalid Duration",
   906  			schema:      `{"type": "fixed", "name":"test", "size": 11, "logicalType": "duration"}`,
   907  			wantType:    avro.Fixed,
   908  			wantLogical: false,
   909  		},
   910  		{
   911  			name:            "Bytes Decimal",
   912  			schema:          `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`,
   913  			wantType:        avro.Bytes,
   914  			wantLogical:     true,
   915  			wantLogicalType: avro.Decimal,
   916  			assertFn: func(t *testing.T, ls avro.LogicalSchema) {
   917  				dec, ok := ls.(*avro.DecimalLogicalSchema)
   918  				if assert.True(t, ok) {
   919  					assert.Equal(t, 4, dec.Precision())
   920  					assert.Equal(t, 2, dec.Scale())
   921  				}
   922  			},
   923  		},
   924  		{
   925  			name:            "Bytes Decimal No Scale",
   926  			schema:          `{"type": "bytes", "logicalType": "decimal", "precision": 4}`,
   927  			wantType:        avro.Bytes,
   928  			wantLogical:     true,
   929  			wantLogicalType: avro.Decimal,
   930  			assertFn: func(t *testing.T, ls avro.LogicalSchema) {
   931  				dec, ok := ls.(*avro.DecimalLogicalSchema)
   932  				if assert.True(t, ok) {
   933  					assert.Equal(t, 4, dec.Precision())
   934  					assert.Equal(t, 0, dec.Scale())
   935  				}
   936  			},
   937  		},
   938  		{
   939  			name:        "Bytes Decimal Negative Precision",
   940  			schema:      `{"type": "bytes", "logicalType": "decimal", "precision": 0}`,
   941  			wantType:    avro.Bytes,
   942  			wantLogical: false,
   943  		},
   944  		{
   945  			name:        "Bytes Decimal Negative Scale",
   946  			schema:      `{"type": "bytes", "logicalType": "decimal", "precision": 1, "scale": -1}`,
   947  			wantType:    avro.Bytes,
   948  			wantLogical: false,
   949  		},
   950  		{
   951  			name:        "Bytes Decimal Scale Larger Than Precision",
   952  			schema:      `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 6}`,
   953  			wantType:    avro.Bytes,
   954  			wantLogical: false,
   955  		},
   956  		{
   957  			name:            "Fixed Decimal",
   958  			schema:          `{"type": "fixed", "name":"test", "size": 12, "logicalType": "decimal", "precision": 4, "scale": 2}`,
   959  			wantType:        avro.Fixed,
   960  			wantLogical:     true,
   961  			wantLogicalType: avro.Decimal,
   962  			assertFn: func(t *testing.T, ls avro.LogicalSchema) {
   963  				dec, ok := ls.(*avro.DecimalLogicalSchema)
   964  				if assert.True(t, ok) {
   965  					assert.Equal(t, 4, dec.Precision())
   966  					assert.Equal(t, 2, dec.Scale())
   967  				}
   968  			},
   969  		},
   970  		{
   971  			name:            "Fixed Decimal No Scale",
   972  			schema:          `{"type": "fixed", "name":"test", "size": 12, "logicalType": "decimal", "precision": 4}`,
   973  			wantType:        avro.Fixed,
   974  			wantLogical:     true,
   975  			wantLogicalType: avro.Decimal,
   976  			assertFn: func(t *testing.T, ls avro.LogicalSchema) {
   977  				dec, ok := ls.(*avro.DecimalLogicalSchema)
   978  				if assert.True(t, ok) {
   979  					assert.Equal(t, 4, dec.Precision())
   980  					assert.Equal(t, 0, dec.Scale())
   981  				}
   982  			},
   983  		},
   984  		{
   985  			name:        "Fixed Decimal Negative Precision",
   986  			schema:      `{"type": "fixed", "name":"test", "size": 12, "logicalType": "decimal", "precision": 0}`,
   987  			wantType:    avro.Fixed,
   988  			wantLogical: false,
   989  		},
   990  		{
   991  			name:        "Fixed Decimal Precision Too Large",
   992  			schema:      `{"type": "fixed", "name":"test", "size": 4, "logicalType": "decimal", "precision": 10}`,
   993  			wantType:    avro.Fixed,
   994  			wantLogical: false,
   995  		},
   996  		{
   997  			name:        "Fixed Decimal Scale Larger Than Precision",
   998  			schema:      `{"type": "fixed", "name":"test", "size": 12, "logicalType": "decimal", "precision": 4, "scale": 6}`,
   999  			wantType:    avro.Fixed,
  1000  			wantLogical: false,
  1001  		},
  1002  	}
  1003  
  1004  	for _, tt := range tests {
  1005  		t.Run(tt.name, func(t *testing.T) {
  1006  			schema, err := avro.Parse(tt.schema)
  1007  
  1008  			assert.NoError(t, err)
  1009  			assert.Equal(t, tt.wantType, schema.Type())
  1010  
  1011  			lts, ok := schema.(avro.LogicalTypeSchema)
  1012  			if !ok {
  1013  				assert.Fail(t, "logical type schema expected")
  1014  				return
  1015  			}
  1016  
  1017  			ls := lts.Logical()
  1018  			if assert.Equal(t, tt.wantLogical, ls != nil) {
  1019  				if !tt.wantLogical {
  1020  					return
  1021  				}
  1022  
  1023  				assert.Equal(t, tt.wantLogicalType, ls.Type())
  1024  
  1025  				if tt.assertFn != nil {
  1026  					tt.assertFn(t, ls)
  1027  				}
  1028  			}
  1029  		})
  1030  	}
  1031  }
  1032  
  1033  func TestSchema_FingerprintUsing(t *testing.T) {
  1034  	tests := []struct {
  1035  		name   string
  1036  		schema string
  1037  		typ    avro.FingerprintType
  1038  		want   []byte
  1039  	}{
  1040  
  1041  		{
  1042  			name:   "Null CRC64",
  1043  			schema: "null",
  1044  			typ:    avro.CRC64Avro,
  1045  			want:   []byte{0x63, 0xdd, 0x24, 0xe7, 0xcc, 0x25, 0x8f, 0x8a},
  1046  		},
  1047  		{
  1048  			name:   "Null MD5",
  1049  			schema: "null",
  1050  			typ:    avro.MD5,
  1051  			want:   []byte{0x9b, 0x41, 0xef, 0x67, 0x65, 0x1c, 0x18, 0x48, 0x8a, 0x8b, 0x8, 0xbb, 0x67, 0xc7, 0x56, 0x99},
  1052  		},
  1053  		{
  1054  			name:   "Null SHA256",
  1055  			schema: "null",
  1056  			typ:    avro.SHA256,
  1057  			want:   []byte{0xf0, 0x72, 0xcb, 0xec, 0x3b, 0xf8, 0x84, 0x18, 0x71, 0xd4, 0x28, 0x42, 0x30, 0xc5, 0xe9, 0x83, 0xdc, 0x21, 0x1a, 0x56, 0x83, 0x7a, 0xed, 0x86, 0x24, 0x87, 0x14, 0x8f, 0x94, 0x7d, 0x1a, 0x1f},
  1058  		},
  1059  		{
  1060  			name:   "Primitive CRC64",
  1061  			schema: "string",
  1062  			typ:    avro.CRC64Avro,
  1063  			want:   []byte{0x8f, 0x1, 0x48, 0x72, 0x63, 0x45, 0x3, 0xc7},
  1064  		},
  1065  		{
  1066  			name:   "Record CRC64",
  1067  			schema: `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "doc": "docs", "fields":[{"name": "field", "type": "int"}]}`,
  1068  			typ:    avro.CRC64Avro,
  1069  			want:   []byte{0xaf, 0x30, 0x30, 0xf0, 0x1c, 0x99, 0x76, 0xda},
  1070  		},
  1071  		{
  1072  			name:   "Enum CRC64",
  1073  			schema: `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
  1074  			typ:    avro.CRC64Avro,
  1075  			want:   []byte{0xc, 0xb0, 0xa2, 0xa6, 0x5f, 0x96, 0x8, 0xd1},
  1076  		},
  1077  		{
  1078  			name:   "Array CRC64",
  1079  			schema: `{"type":"array", "items": "int"}`,
  1080  			typ:    avro.CRC64Avro,
  1081  			want:   []byte{0x52, 0x2b, 0x81, 0x4f, 0xc9, 0x63, 0xb4, 0xbe},
  1082  		},
  1083  		{
  1084  			name:   "Map CRC64",
  1085  			schema: `{"type":"map", "values": "int"}`,
  1086  			typ:    avro.CRC64Avro,
  1087  			want:   []byte{0xdb, 0x39, 0xe2, 0xc2, 0x53, 0x4c, 0x89, 0x73},
  1088  		},
  1089  		{
  1090  			name:   "Union CRC64",
  1091  			schema: `["null", "int"]`,
  1092  			typ:    avro.CRC64Avro,
  1093  			want:   []byte{0xd5, 0x1c, 0xc0, 0x92, 0x2b, 0x46, 0xb1, 0xd7},
  1094  		},
  1095  		{
  1096  			name:   "Fixed CRC64",
  1097  			schema: `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}`,
  1098  			typ:    avro.CRC64Avro,
  1099  			want:   []byte{0x1, 0x7c, 0x1f, 0x7f, 0xa7, 0x6d, 0xa0, 0xa1},
  1100  		},
  1101  	}
  1102  
  1103  	for _, tt := range tests {
  1104  		t.Run(tt.name, func(t *testing.T) {
  1105  			schema := avro.MustParse(tt.schema)
  1106  			got, err := schema.FingerprintUsing(tt.typ)
  1107  
  1108  			if assert.NoError(t, err) {
  1109  				assert.Equal(t, tt.want, got)
  1110  			}
  1111  		})
  1112  	}
  1113  }
  1114  
  1115  func TestSchema_FingerprintUsingReference(t *testing.T) {
  1116  	schema := avro.MustParse(`
  1117  {
  1118     "type": "record",
  1119     "name": "valid_name",
  1120     "namespace": "org.hamba.avro",
  1121     "fields": [
  1122         {"name": "intField", "type": "int"},
  1123         {"name": "Ref", "type": "valid_name"}
  1124     ]
  1125  }
  1126  `)
  1127  
  1128  	got, err := schema.(*avro.RecordSchema).Fields()[1].Type().FingerprintUsing(avro.CRC64Avro)
  1129  
  1130  	assert.NoError(t, err)
  1131  	assert.Equal(t, []byte{0xe1, 0xd6, 0x1e, 0x7c, 0x2f, 0xe3, 0x3c, 0x2b}, got)
  1132  }
  1133  
  1134  func TestSchema_FingerprintUsingInvalidType(t *testing.T) {
  1135  	schema := avro.MustParse("string")
  1136  
  1137  	_, err := schema.FingerprintUsing("test")
  1138  
  1139  	assert.Error(t, err)
  1140  }
  1141  
  1142  func TestSchema_Interop(t *testing.T) {
  1143  	schm := `
  1144  {
  1145     "type": "record",
  1146     "name": "Interop",
  1147     "namespace": "org.hamba.avro",
  1148     "fields": [
  1149         {
  1150             "name": "intField",
  1151             "type": "int"
  1152         },
  1153         {
  1154             "name": "longField",
  1155             "type": "long"
  1156         },
  1157         {
  1158             "name": "stringField",
  1159             "type": "string"
  1160         },
  1161         {
  1162             "name": "boolField",
  1163             "type": "boolean"
  1164         },
  1165         {
  1166             "name": "floatField",
  1167             "type": "float"
  1168         },
  1169         {
  1170             "name": "doubleField",
  1171             "type": "double"
  1172         },
  1173         {
  1174             "name": "bytesField",
  1175             "type": "bytes"
  1176         },
  1177         {
  1178             "name": "nullField",
  1179             "type": "null"
  1180         },
  1181         {
  1182             "name": "arrayField",
  1183             "type": {
  1184                 "type": "array",
  1185                 "items": "double"
  1186             }
  1187         },
  1188         {
  1189             "name": "mapField",
  1190             "type": {
  1191                 "type": "map",
  1192                 "values": {
  1193                     "type": "record",
  1194                     "name": "Foo",
  1195                     "fields": [
  1196                         {
  1197                             "name": "label",
  1198                             "type": "string"
  1199                         }
  1200                     ]
  1201                 }
  1202             }
  1203         },
  1204         {
  1205             "name": "unionField",
  1206             "type": [
  1207                 "boolean",
  1208                 "double",
  1209                 {
  1210                     "type": "array",
  1211                     "items": "bytes"
  1212                 }
  1213             ]
  1214         },
  1215         {
  1216             "name": "enumField",
  1217             "type": {
  1218                 "type": "enum",
  1219                 "name": "Kind",
  1220                 "symbols": [
  1221                     "A",
  1222                     "B",
  1223                     "C"
  1224                 ]
  1225             }
  1226         },
  1227         {
  1228             "name": "fixedField",
  1229             "type": {
  1230                 "type": "fixed",
  1231                 "name": "MD5",
  1232                 "size": 16
  1233             }
  1234         },
  1235         {
  1236             "name": "recordField",
  1237             "type": {
  1238                 "type": "record",
  1239                 "name": "Node",
  1240                 "fields": [
  1241                     {
  1242                         "name": "label",
  1243                         "type": "string"
  1244                     },
  1245                     {
  1246                         "name": "child",
  1247                         "type": {"type": "org.hamba.avro.Node"}
  1248                     },
  1249                     {
  1250                         "name": "children",
  1251                         "type": {
  1252                             "type": "array",
  1253                             "items": "Node"
  1254                         }
  1255                     }
  1256                 ]
  1257             }
  1258         }
  1259     ]
  1260  }`
  1261  
  1262  	_, err := avro.Parse(schm)
  1263  
  1264  	assert.NoError(t, err)
  1265  }