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 }