Repository: hamba/avro
Pull request #165 (2022-06-14 05:22:11)

chore: cleanup code + tests
This PR cleans the code and tests up a little. It also switches the `strcase` lib to allow for handling Go  initialisms.


Patch:
diff --git a/gen/gen.go b/gen/gen.go
index 92b1a7d..c39fa25 100644
--- a/gen/gen.go
+++ b/gen/gen.go
@@ -10,8 +10,8 @@ import (
 	"strings"
 	"text/template"
 
+	"github.com/ettle/strcase"
 	"github.com/hamba/avro"
-	"github.com/iancoleman/strcase"
 )
 
 // Config exposes the options available for the code generation.
@@ -20,10 +20,6 @@ type Config struct {
 	Tags        map[string]TagStyle
 }
 
-type generator struct {
-	Config
-}
-
 // TagStyle defines the styling for a tag.
 type TagStyle string
 
@@ -84,13 +80,18 @@ var primitiveMappings = map[avro.Type]string{
 	"boolean": "bool",
 }
 
-// Struct generates Go structs based on the schema s and writes them to dst.
-func Struct(s string, dst io.Writer, gc Config) error {
+// Struct generates Go structs based on the schema and writes them to w.
+func Struct(s string, w io.Writer, gc Config) error {
 	schema, err := avro.Parse(s)
 	if err != nil {
 		return err
 	}
 
+	return StructFromSchema(schema, w, gc)
+}
+
+// StructFromSchema generates Go structs based on the schema and writes them to w.
+func StructFromSchema(schema avro.Schema, w io.Writer, gc Config) error {
 	rSchema, ok := schema.(*avro.RecordSchema)
 	if !ok {
 		return errors.New("can only generate Go code from Record Schemas")
@@ -100,7 +101,7 @@ func Struct(s string, dst io.Writer, gc Config) error {
 	_ = generator{Config: gc}.generateFrom(rSchema, &td)
 
 	buf := &bytes.Buffer{}
-	if err = writeCode(buf, &td); err != nil {
+	if err := writeCode(buf, &td); err != nil {
 		return err
 	}
 
@@ -109,18 +110,22 @@ func Struct(s string, dst io.Writer, gc Config) error {
 		return fmt.Errorf("failed formatting. %w", err)
 	}
 
-	_, err = dst.Write(formatted)
+	_, err = w.Write(formatted)
 	return err
 }
 
+type generator struct {
+	Config
+}
+
 func (g generator) generateFrom(schema avro.Schema, acc *data) string {
 	switch t := schema.(type) {
 	case *avro.RecordSchema:
-		typeName := strcase.ToCamel(t.Name())
+		typeName := strcase.ToGoPascal(t.Name())
 		fields := make([]field, len(t.Fields()))
 		for i, f := range t.Fields() {
 			fSchema := f.Type()
-			fieldName := strcase.ToCamel(f.Name())
+			fieldName := strcase.ToGoPascal(f.Name())
 			typ := g.resolveType(fSchema, acc)
 			tag := f.Name()
 			fields[i] = g.newField(fieldName, typ, tag)
@@ -170,7 +175,7 @@ func resolveRefSchema(s *avro.RefSchema) string {
 	if sx, ok := s.Schema().(*avro.RecordSchema); ok {
 		typ = sx.Name()
 	}
-	return strcase.ToCamel(typ)
+	return strcase.ToGoPascal(typ)
 }
 
 func (g generator) resolveUnionTypes(unionSchema *avro.UnionSchema, acc *data) string {
@@ -241,9 +246,9 @@ func (g generator) tagStyleFn(style TagStyle) func(string) string {
 	case Kebab:
 		return strcase.ToKebab
 	case UpperCamel:
-		return strcase.ToCamel
+		return strcase.ToPascal
 	case Camel:
-		return strcase.ToLowerCamel
+		return strcase.ToCamel
 	case Snake:
 		return strcase.ToSnake
 	}
diff --git a/go.mod b/go.mod
index cb2f2ef..3b0d13e 100644
--- a/go.mod
+++ b/go.mod
@@ -3,8 +3,8 @@ module github.com/hamba/avro
 go 1.11
 
 require (
+	github.com/ettle/strcase v0.1.1
 	github.com/golang/snappy v0.0.4
-	github.com/iancoleman/strcase v0.2.0
 	github.com/json-iterator/go v1.1.12
 	github.com/kr/pretty v0.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0
diff --git a/go.sum b/go.sum
index e7d04bf..bba1bdd 100644
--- a/go.sum
+++ b/go.sum
@@ -1,11 +1,11 @@
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw=
+github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
-github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -24,10 +24,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/reader.go b/reader.go
index ff3c19b..9169fc9 100644
--- a/reader.go
+++ b/reader.go
@@ -179,7 +179,6 @@ func (r *Reader) ReadLong() int64 {
 		if b&0x80 == 0 {
 			break
 		}
-
 		offset++
 	}
 


Test patch:
diff --git a/gen/gen_test.go b/gen/gen_test.go
index f55a1ea..7fa9649 100644
--- a/gen/gen_test.go
+++ b/gen/gen_test.go
@@ -2,8 +2,9 @@ package gen_test
 
 import (
 	"bytes"
+	"flag"
 	"fmt"
-	"io"
+	"os"
 	"regexp"
 	"strings"
 	"testing"
@@ -13,18 +14,23 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
-func TestInvalidSchemaYieldsErr(t *testing.T) {
-	require.Error(t, gen.Struct(`asd`, &bytes.Buffer{}, gen.Config{}))
+var update = flag.Bool("update", false, "Update golden files")
+
+func TestStruct_InvalidSchemaYieldsErr(t *testing.T) {
+	err := gen.Struct(`asd`, &bytes.Buffer{}, gen.Config{})
+
+	assert.Error(t, err)
 }
 
-func TestNonRecordSchemasAreNotSupported(t *testing.T) {
+func TestStruct_NonRecordSchemasAreNotSupported(t *testing.T) {
 	err := gen.Struct(`{"type": "string"}`, &bytes.Buffer{}, gen.Config{})
+
 	require.Error(t, err)
 	assert.Contains(t, strings.ToLower(err.Error()), "only")
 	assert.Contains(t, strings.ToLower(err.Error()), "record schema")
 }
 
-func TestAvroStyleCannotBeOverriden(t *testing.T) {
+func TestStruct_AvroStyleCannotBeOverridden(t *testing.T) {
 	schema := `{
   "type": "record",
   "name": "test",
@@ -39,8 +45,7 @@ func TestAvroStyleCannotBeOverriden(t *testing.T) {
 		},
 	}
 
-	goCode, lines := generate(t, schema, gc)
-	fmt.Printf("Generated code:\n%s\n", string(goCode))
+	_, lines := generate(t, schema, gc)
 
 	for _, expected := range []string{
 		"package something",
@@ -52,7 +57,24 @@ func TestAvroStyleCannotBeOverriden(t *testing.T) {
 	}
 }
 
-func TestConfigurableFieldTags(t *testing.T) {
+func TestStruct_HandlesGoInitialisms(t *testing.T) {
+	schema := `{
+  "type": "record",
+  "name": "httpRecord",
+  "fields": [
+    { "name": "someString", "type": "string" }
+  ]
+}`
+	gc := gen.Config{
+		PackageName: "Something",
+	}
+
+	_, lines := generate(t, schema, gc)
+
+	assert.Contains(t, lines, "type HTTPRecord struct {")
+}
+
+func TestStruct_ConfigurableFieldTags(t *testing.T) {
 	schema := `{
   "type": "record",
   "name": "test",
@@ -61,7 +83,7 @@ func TestConfigurableFieldTags(t *testing.T) {
   ]
 }`
 
-	for _, tc := range []struct {
+	tests := []struct {
 		tagStyle    gen.TagStyle
 		expectedTag string
 	}{
@@ -69,19 +91,24 @@ func TestConfigurableFieldTags(t *testing.T) {
 		{tagStyle: gen.Snake, expectedTag: "json:\"some_string\""},
 		{tagStyle: gen.Kebab, expectedTag: "json:\"some-string\""},
 		{tagStyle: gen.UpperCamel, expectedTag: "json:\"SomeString\""},
-	} {
-		t.Run(fmt.Sprintf("%s", tc.tagStyle), func(t *testing.T) {
-			gc := gen.Config{PackageName: "Something", Tags: map[string]gen.TagStyle{
-				"json": tc.tagStyle,
-			}}
-			goCode, lines := generate(t, schema, gc)
+		{tagStyle: gen.TagStyle(""), expectedTag: "json:\"someString\""},
+	}
 
-			fmt.Printf("Generated code:\n%s\n", string(goCode))
+	for _, test := range tests {
+		test := test
+		t.Run(fmt.Sprintf("%s", test.tagStyle), func(t *testing.T) {
+			gc := gen.Config{
+				PackageName: "Something",
+				Tags: map[string]gen.TagStyle{
+					"json": test.tagStyle,
+				},
+			}
+			_, lines := generate(t, schema, gc)
 
 			for _, expected := range []string{
 				"package something",
 				"type Test struct {",
-				fmt.Sprintf("SomeString string `avro:\"someString\" %s`", tc.expectedTag),
+				fmt.Sprintf("SomeString string `avro:\"someString\" %s`", test.expectedTag),
 				"}",
 			} {
 				assert.Contains(t, lines, expected)
@@ -90,341 +117,35 @@ func TestConfigurableFieldTags(t *testing.T) {
 	}
 }
 
-func TestGenFromRecordSchema(t *testing.T) {
-	schema := `{
-  "type": "record",
-  "name": "test",
-  "fields": [
-    {
-      "name": "aString",
-      "type": "string"
-    },
-    {
-      "name": "aBoolean",
-      "type": "boolean"
-    },
-    {
-      "name": "anInt",
-      "type": "int"
-    },
-    {
-      "name": "aFloat",
-      "type": "float"
-    },
-    {
-      "name": "aDouble",
-      "type": "double"
-    },
-    {
-      "name": "aLong",
-      "type": "long"
-    },
-    {
-      "name": "justBytes",
-      "type": "bytes"
-    },
-    {
-      "name": "primitiveNullableArrayUnion",
-      "type": [
-        "null",
-        {
-          "type": "array",
-          "items": "string"
-        }
-      ],
-      "default": null
-    },
-    {
-      "name": "innerRecord",
-      "type": {
-        "name": "InnerRecord",
-        "type": "record",
-        "fields": [
-          {
-            "name": "innerJustBytes",
-            "type": "bytes"
-          },
-          {
-            "name": "innerPrimitiveNullableArrayUnion",
-            "type": [
-              "null",
-              {
-                "type": "array",
-                "items": "string"
-              }
-            ],
-            "default": null
-          }
-        ]
-      }
-    },
-    {
-      "name": "anEnum",
-      "type": {
-        "type": "enum",
-        "name": "Cards",
-        "symbols": [
-          "SPADES",
-          "HEARTS",
-          "DIAMONDS",
-          "CLUBS"
-        ]
-      }
-    },
-    {
-      "name": "aFixed",
-      "type": {
-        "type": "fixed",
-        "name": "fixedField",
-        "size": 7
-      }
-    },
-    {
-      "name": "aLogicalFixed",
-      "type": {
-        "type": "fixed",
-        "name": "test",
-        "size": 12,
-        "logicalType": "duration"
-      }
-    },
-    {
-      "name": "mapOfStrings",
-      "type": {
-        "name": "aMapOfStrings",
-        "type": "map",
-        "values": "string"
-      }
-    },
-    {
-      "name": "mapOfRecords",
-      "type": {
-        "name": "aMapOfRecords",
-        "type": "map",
-        "values": {
-          "name": "RecordInMap",
-          "type": "record",
-          "fields": [
-            {
-              "type": "string",
-              "name": "name"
-            }
-          ]
-        }
-      }
-    },
-    {
-      "name": "aDate",
-      "type": {
-        "type": "int",
-        "logicalType": "date"
-      }
-    },
-    {
-      "name": "aDuration",
-      "type": {
-        "type": "int",
-        "logicalType": "time-millis"
-      }
-    },
-    {
-      "name": "aLongTimeMicros",
-      "type": {
-        "type": "long",
-        "logicalType": "time-micros"
-      }
-    },
-    {
-      "name": "aLongTimestampMillis",
-      "type": {
-        "type": "long",
-        "logicalType": "timestamp-millis"
-      }
-    },
-    {
-      "name": "aLongTimestampMicro",
-      "type": {
-        "type": "long",
-        "logicalType": "timestamp-micros"
-      }
-    },
-    {
-      "name": "aBytesDecimal",
-      "type": {
-        "type": "bytes",
-        "logicalType": "decimal",
-        "precision": 4,
-        "scale": 2
-      }
-    },
-    {
-      "name": "aRecordArray",
-      "type": {
-        "name": "someRecordArray",
-        "type": "array",
-        "items": {
-          "name": "recordInArray",
-          "type": "record",
-          "fields": [
-            {
-              "type": "string",
-              "name": "aString"
-            }
-          ]
-        }
-      }
-    },
-    {
-      "name": "nullableRecordUnion",
-      "type": [
-        "null",
-        {
-          "name": "recordInNullableUnion",
-          "type": "record",
-          "fields": [
-            {
-              "name": "aString",
-              "type": "string"
-            }
-          ]
-        }
-      ],
-      "default": null
-    },
-    {
-      "name": "nonNullableRecordUnion",
-      "type": [
-        {
-          "name": "record1InNonNullableUnion",
-          "type": "record",
-          "fields": [
-            {
-              "name": "aString",
-              "type": "string"
-            }
-          ]
-        },
-        {
-          "name": "record2InNonNullableUnion",
-          "type": "record",
-          "fields": [
-            {
-              "name": "aString",
-              "type": "string"
-            }
-          ]
-        }
-      ]
-    },
-    {
-      "name": "nullableRecordUnionWith3Options",
-      "type": [
-        "null",
-        {
-          "name": "record1InNullableUnion",
-          "type": "record",
-          "fields": [
-            {
-              "name": "aString",
-              "type": "string"
-            }
-          ]
-        },
-        {
-          "name": "record2InNullableUnion",
-          "type": "record",
-          "fields": [
-            {
-              "name": "aString",
-              "type": "string"
-            }
-          ]
-        }
-      ],
-      "default": null
-    },
-    {
-      "name": "ref",
-      "type": "record2InNullableUnion"
-    }
-  ]
-}`
+func TestStruct_GenFromRecordSchema(t *testing.T) {
+	schema, err := os.ReadFile("testdata/golden.avsc")
+	require.NoError(t, err)
 
 	gc := gen.Config{PackageName: "Something"}
-	goCode, lines := generate(t, schema, gc)
+	file, _ := generate(t, string(schema), gc)
 
-	fmt.Printf("Generated code:\n%s\n", string(goCode))
-
-	for _, expected := range []string{
-		"package something",
-		"import (",
-		"\"math/big\"",
-		"\"time\"",
-		")",
-		"type Test struct {",
-		"AString string `avro:\"aString\"`",
-		"ABoolean bool `avro:\"aBoolean\"`",
-		"AnInt int `avro:\"anInt\"`",
-		"AFloat float32 `avro:\"aFloat\"`",
-		"ADouble float64 `avro:\"aDouble\"`",
-		"ALong int64 `avro:\"aLong\"`",
-		"JustBytes []byte `avro:\"justBytes\"`",
-		"PrimitiveNullableArrayUnion []string `avro:\"primitiveNullableArrayUnion\"`",
-		"InnerRecord InnerRecord `avro:\"innerRecord\"`",
-		"AnEnum string `avro:\"anEnum\"`",
-		"AFixed [7]byte `avro:\"aFixed\"`",
-		"ALogicalFixed time.Duration `avro:\"aLogicalFixed\"`",
-		"MapOfStrings map[string]string `avro:\"mapOfStrings\"`",
-		"MapOfRecords map[string]RecordInMap `avro:\"mapOfRecords\"`",
-		"ADate time.Time `avro:\"aDate\"`",
-		"ADuration time.Duration `avro:\"aDuration\"`",
-		"ALongTimeMicros time.Duration `avro:\"aLongTimeMicros\"`",
-		"ALongTimestampMillis time.Time `avro:\"aLongTimestampMillis\"`",
-		"ALongTimestampMicro time.Time `avro:\"aLongTimestampMicro\"`",
-		"ABytesDecimal *big.Rat `avro:\"aBytesDecimal\"`",
-		"NullableRecordUnion *RecordInNullableUnion `avro:\"nullableRecordUnion\"`",
-		"NonNullableRecordUnion interface{} `avro:\"nonNullableRecordUnion\"`",
-		"NullableRecordUnionWith3Options interface{} `avro:\"nullableRecordUnionWith3Options\"`",
-		"Ref Record2InNullableUnion `avro:\"ref\"`",
-		"}",
-		"type InnerRecord struct {",
-		"InnerJustBytes []byte `avro:\"innerJustBytes\"`",
-		"InnerPrimitiveNullableArrayUnion []string `avro:\"innerPrimitiveNullableArrayUnion\"`",
-		"}",
-		"type RecordInMap struct {",
-		"Name string `avro:\"name\"`",
-		"}",
-		"type RecordInArray struct {",
-		"AString string `avro:\"aString\"`",
-		"}",
-		"type Record1InNonNullableUnion struct {",
-		"AString string `avro:\"aString\"`",
-		"}",
-		"type Record2InNonNullableUnion struct {",
-		"AString string `avro:\"aString\"`",
-		"}",
-		"type RecordInNullableUnion struct {",
-		"AString string `avro:\"aString\"`",
-		"}",
-		"type Record1InNullableUnion struct {",
-		"AString string `avro:\"aString\"`",
-		"}",
-		"type Record2InNullableUnion struct {",
-		"AString string `avro:\"aString\"`",
-		"}",
-	} {
-		assert.Contains(t, lines, expected)
+	if *update {
+		err = os.WriteFile("testdata/golden.go", file, 0600)
+		require.NoError(t, err)
 	}
+
+	want, err := os.ReadFile("testdata/golden.go")
+	require.NoError(t, err)
+	assert.Equal(t, want, file)
 }
 
 // generate is a utility to run the generation and return the result as a tuple
 func generate(t *testing.T, schema string, gc gen.Config) ([]byte, []string) {
+	t.Helper()
+
 	buf := &bytes.Buffer{}
 	err := gen.Struct(schema, buf, gc)
 	require.NoError(t, err)
-	goCode, err := io.ReadAll(buf)
-	require.NoError(t, err)
-	return goCode, removeSpaceAndEmptyLines(goCode)
+
+	b := make([]byte, buf.Len())
+	copy(b, buf.Bytes())
+
+	return buf.Bytes(), removeSpaceAndEmptyLines(b)
 }
 
 func removeSpaceAndEmptyLines(goCode []byte) []string {
@@ -441,5 +162,6 @@ func removeSpaceAndEmptyLines(goCode []byte) []string {
 
 // removeMoreThanOneConsecutiveSpaces replaces all sequences of more than one space, with a single one
 func removeMoreThanOneConsecutiveSpaces(lineBytes []byte) string {
-	return strings.Join(regexp.MustCompile("\\s+|\\t+").Split(strings.TrimSpace(string(lineBytes)), -1), " ")
+	lines := strings.TrimSpace(string(lineBytes))
+	return strings.Join(regexp.MustCompile("\\s+|\\t+").Split(lines, -1), " ")
 }
diff --git a/gen/testdata/golden.avsc b/gen/testdata/golden.avsc
new file mode 100644
index 0000000..ad6e6d4
--- /dev/null
+++ b/gen/testdata/golden.avsc
@@ -0,0 +1,258 @@
+{
+  "type": "record",
+  "name": "test",
+  "fields": [
+    {
+      "name": "aString",
+      "type": "string"
+    },
+    {
+      "name": "aBoolean",
+      "type": "boolean"
+    },
+    {
+      "name": "anInt",
+      "type": "int"
+    },
+    {
+      "name": "aFloat",
+      "type": "float"
+    },
+    {
+      "name": "aDouble",
+      "type": "double"
+    },
+    {
+      "name": "aLong",
+      "type": "long"
+    },
+    {
+      "name": "justBytes",
+      "type": "bytes"
+    },
+    {
+      "name": "primitiveNullableArrayUnion",
+      "type": [
+        "null",
+        {
+          "type": "array",
+          "items": "string"
+        }
+      ],
+      "default": null
+    },
+    {
+      "name": "innerRecord",
+      "type": {
+        "name": "InnerRecord",
+        "type": "record",
+        "fields": [
+          {
+            "name": "innerJustBytes",
+            "type": "bytes"
+          },
+          {
+            "name": "innerPrimitiveNullableArrayUnion",
+            "type": [
+              "null",
+              {
+                "type": "array",
+                "items": "string"
+              }
+            ],
+            "default": null
+          }
+        ]
+      }
+    },
+    {
+      "name": "anEnum",
+      "type": {
+        "type": "enum",
+        "name": "Cards",
+        "symbols": [
+          "SPADES",
+          "HEARTS",
+          "DIAMONDS",
+          "CLUBS"
+        ]
+      }
+    },
+    {
+      "name": "aFixed",
+      "type": {
+        "type": "fixed",
+        "name": "fixedField",
+        "size": 7
+      }
+    },
+    {
+      "name": "aLogicalFixed",
+      "type": {
+        "type": "fixed",
+        "name": "test",
+        "size": 12,
+        "logicalType": "duration"
+      }
+    },
+    {
+      "name": "mapOfStrings",
+      "type": {
+        "name": "aMapOfStrings",
+        "type": "map",
+        "values": "string"
+      }
+    },
+    {
+      "name": "mapOfRecords",
+      "type": {
+        "name": "aMapOfRecords",
+        "type": "map",
+        "values": {
+          "name": "RecordInMap",
+          "type": "record",
+          "fields": [
+            {
+              "type": "string",
+              "name": "name"
+            }
+          ]
+        }
+      }
+    },
+    {
+      "name": "aDate",
+      "type": {
+        "type": "int",
+        "logicalType": "date"
+      }
+    },
+    {
+      "name": "aDuration",
+      "type": {
+        "type": "int",
+        "logicalType": "time-millis"
+      }
+    },
+    {
+      "name": "aLongTimeMicros",
+      "type": {
+        "type": "long",
+        "logicalType": "time-micros"
+      }
+    },
+    {
+      "name": "aLongTimestampMillis",
+      "type": {
+        "type": "long",
+        "logicalType": "timestamp-millis"
+      }
+    },
+    {
+      "name": "aLongTimestampMicro",
+      "type": {
+        "type": "long",
+        "logicalType": "timestamp-micros"
+      }
+    },
+    {
+      "name": "aBytesDecimal",
+      "type": {
+        "type": "bytes",
+        "logicalType": "decimal",
+        "precision": 4,
+        "scale": 2
+      }
+    },
+    {
+      "name": "aRecordArray",
+      "type": {
+        "name": "someRecordArray",
+        "type": "array",
+        "items": {
+          "name": "recordInArray",
+          "type": "record",
+          "fields": [
+            {
+              "type": "string",
+              "name": "aString"
+            }
+          ]
+        }
+      }
+    },
+    {
+      "name": "nullableRecordUnion",
+      "type": [
+        "null",
+        {
+          "name": "recordInNullableUnion",
+          "type": "record",
+          "fields": [
+            {
+              "name": "aString",
+              "type": "string"
+            }
+          ]
+        }
+      ],
+      "default": null
+    },
+    {
+      "name": "nonNullableRecordUnion",
+      "type": [
+        {
+          "name": "record1InNonNullableUnion",
+          "type": "record",
+          "fields": [
+            {
+              "name": "aString",
+              "type": "string"
+            }
+          ]
+        },
+        {
+          "name": "record2InNonNullableUnion",
+          "type": "record",
+          "fields": [
+            {
+              "name": "aString",
+              "type": "string"
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "name": "nullableRecordUnionWith3Options",
+      "type": [
+        "null",
+        {
+          "name": "record1InNullableUnion",
+          "type": "record",
+          "fields": [
+            {
+              "name": "aString",
+              "type": "string"
+            }
+          ]
+        },
+        {
+          "name": "record2InNullableUnion",
+          "type": "record",
+          "fields": [
+            {
+              "name": "aString",
+              "type": "string"
+            }
+          ]
+        }
+      ],
+      "default": null
+    },
+    {
+      "name": "ref",
+      "type": "record2InNullableUnion"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/gen/testdata/golden.go b/gen/testdata/golden.go
new file mode 100644
index 0000000..f43b985
--- /dev/null
+++ b/gen/testdata/golden.go
@@ -0,0 +1,68 @@
+// Code generated by avro/gen. DO NOT EDIT.
+package something
+
+import (
+	"math/big"
+	"time"
+)
+
+type InnerRecord struct {
+	InnerJustBytes                   []byte   `avro:"innerJustBytes"`
+	InnerPrimitiveNullableArrayUnion []string `avro:"innerPrimitiveNullableArrayUnion"`
+}
+
+type RecordInMap struct {
+	Name string `avro:"name"`
+}
+
+type RecordInArray struct {
+	AString string `avro:"aString"`
+}
+
+type RecordInNullableUnion struct {
+	AString string `avro:"aString"`
+}
+
+type Record1InNonNullableUnion struct {
+	AString string `avro:"aString"`
+}
+
+type Record2InNonNullableUnion struct {
+	AString string `avro:"aString"`
+}
+
+type Record1InNullableUnion struct {
+	AString string `avro:"aString"`
+}
+
+type Record2InNullableUnion struct {
+	AString string `avro:"aString"`
+}
+
+type Test struct {
+	AString                         string                 `avro:"aString"`
+	ABoolean                        bool                   `avro:"aBoolean"`
+	AnInt                           int                    `avro:"anInt"`
+	AFloat                          float32                `avro:"aFloat"`
+	ADouble                         float64                `avro:"aDouble"`
+	ALong                           int64                  `avro:"aLong"`
+	JustBytes                       []byte                 `avro:"justBytes"`
+	PrimitiveNullableArrayUnion     []string               `avro:"primitiveNullableArrayUnion"`
+	InnerRecord                     InnerRecord            `avro:"innerRecord"`
+	AnEnum                          string                 `avro:"anEnum"`
+	AFixed                          [7]byte                `avro:"aFixed"`
+	ALogicalFixed                   time.Duration          `avro:"aLogicalFixed"`
+	MapOfStrings                    map[string]string      `avro:"mapOfStrings"`
+	MapOfRecords                    map[string]RecordInMap `avro:"mapOfRecords"`
+	ADate                           time.Time              `avro:"aDate"`
+	ADuration                       time.Duration          `avro:"aDuration"`
+	ALongTimeMicros                 time.Duration          `avro:"aLongTimeMicros"`
+	ALongTimestampMillis            time.Time              `avro:"aLongTimestampMillis"`
+	ALongTimestampMicro             time.Time              `avro:"aLongTimestampMicro"`
+	ABytesDecimal                   *big.Rat               `avro:"aBytesDecimal"`
+	ARecordArray                    []RecordInArray        `avro:"aRecordArray"`
+	NullableRecordUnion             *RecordInNullableUnion `avro:"nullableRecordUnion"`
+	NonNullableRecordUnion          interface{}            `avro:"nonNullableRecordUnion"`
+	NullableRecordUnionWith3Options interface{}            `avro:"nullableRecordUnionWith3Options"`
+	Ref                             Record2InNullableUnion `avro:"ref"`
+}
diff --git a/reader_generic_test.go b/reader_generic_test.go
index 2bd87fc..5134888 100644
--- a/reader_generic_test.go
+++ b/reader_generic_test.go
@@ -17,7 +17,7 @@ func TestReader_ReadNext(t *testing.T) {
 		data    []byte
 		schema  string
 		want    interface{}
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 
 		{
@@ -25,175 +25,175 @@ func TestReader_ReadNext(t *testing.T) {
 			data:    []byte{0x01},
 			schema:  "boolean",
 			want:    true,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Int",
 			data:    []byte{0x36},
 			schema:  "int",
 			want:    27,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Int Date",
 			data:    []byte{0xAE, 0x9D, 0x02},
 			schema:  `{"type":"int","logicalType":"date"}`,
 			want:    time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Int Time-Millis",
 			data:    []byte{0xAA, 0xB4, 0xDE, 0x75},
 			schema:  `{"type":"int","logicalType":"time-millis"}`,
 			want:    123456789 * time.Millisecond,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Long",
 			data:    []byte{0x36},
 			schema:  "long",
 			want:    int64(27),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Long Time-Micros",
 			data:    []byte{0x86, 0xEA, 0xC8, 0xE9, 0x97, 0x07},
 			schema:  `{"type":"long","logicalType":"time-micros"}`,
 			want:    123456789123 * time.Microsecond,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Long Timestamp-Millis",
 			data:    []byte{0x90, 0xB2, 0xAE, 0xC3, 0xEC, 0x5B},
 			schema:  `{"type":"long","logicalType":"timestamp-millis"}`,
 			want:    time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Long Timestamp-Micros",
 			data:    []byte{0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05},
 			schema:  `{"type":"long","logicalType":"timestamp-micros"}`,
 			want:    time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Float",
 			data:    []byte{0x33, 0x33, 0x93, 0x3F},
 			schema:  "float",
 			want:    float32(1.15),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Double",
 			data:    []byte{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF2, 0x3F},
 			schema:  "double",
 			want:    float64(1.15),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "String",
 			data:    []byte{0x06, 0x66, 0x6F, 0x6F},
 			schema:  "string",
 			want:    "foo",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Bytes",
 			data:    []byte{0x08, 0xEC, 0xAB, 0x44, 0x00},
 			schema:  "bytes",
 			want:    []byte{0xEC, 0xAB, 0x44, 0x00},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Bytes Decimal",
 			data:    []byte{0x6, 0x00, 0x87, 0x78},
 			schema:  `{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}`,
 			want:    big.NewRat(1734, 5),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Record",
 			data:    []byte{0x36, 0x06, 0x66, 0x6f, 0x6f},
 			schema:  `{"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}`,
 			want:    map[string]interface{}{"a": int64(27), "b": "foo"},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Ref",
 			data:    []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x36, 0x06, 0x66, 0x6f, 0x6f},
 			schema:  `{"type":"record","name":"parent","fields":[{"name":"a","type":{"type":"record","name":"test","fields":[{"name":"a","type":"long"},{"name":"b","type":"string"}]}},{"name":"b","type":"test"}]}`,
 			want:    map[string]interface{}{"a": map[string]interface{}{"a": int64(27), "b": "foo"}, "b": map[string]interface{}{"a": int64(27), "b": "foo"}},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Array",
 			data:    []byte{0x04, 0x36, 0x38, 0x0},
 			schema:  `{"type":"array", "items": "int"}`,
 			want:    []interface{}{27, 28},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Map",
 			data:    []byte{0x02, 0x06, 0x66, 0x6F, 0x6F, 0x06, 0x66, 0x6F, 0x6F, 0x00},
 			schema:  `{"type":"map", "values": "string"}`,
 			want:    map[string]interface{}{"foo": "foo"},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Enum",
 			data:    []byte{0x02},
 			schema:  `{"type":"enum", "name": "test", "symbols": ["foo", "bar"]}`,
 			want:    "bar",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Enum Invalid Symbol",
 			data:    []byte{0x04},
 			schema:  `{"type":"enum", "name": "test", "symbols": ["foo", "bar"]}`,
 			want:    nil,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Union",
 			data:    []byte{0x02, 0x06, 0x66, 0x6F, 0x6F},
 			schema:  `["null", "string"]`,
 			want:    map[string]interface{}{"string": "foo"},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Union Nil",
 			data:    []byte{0x00},
 			schema:  `["null", "string"]`,
 			want:    nil,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Union Named",
 			data:    []byte{0x02, 0x02},
 			schema:  `["null", {"type":"enum", "name": "test", "symbols": ["foo", "bar"]}]`,
 			want:    map[string]interface{}{"test": "bar"},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Union Invalid Schema",
 			data:    []byte{0x04},
 			schema:  `["null", "string"]`,
 			want:    nil,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Fixed",
 			data:    []byte{0x66, 0x6F, 0x6F, 0x66, 0x6F, 0x6F},
 			schema:  `{"type":"fixed", "name": "test", "size": 6}`,
 			want:    []byte{'f', 'o', 'o', 'f', 'o', 'o'},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Fixed Decimal",
 			data:    []byte{0x00, 0x00, 0x00, 0x00, 0x87, 0x78},
 			schema:  `{"type":"fixed", "name": "test", "size": 6,"logicalType":"decimal","precision":4,"scale":2}`,
 			want:    big.NewRat(1734, 5),
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 	}
 
@@ -205,12 +205,7 @@ func TestReader_ReadNext(t *testing.T) {
 
 			got := r.ReadNext(schema)
 
-			if test.wantErr {
-				assert.Error(t, r.Error)
-				return
-			}
-
-			require.NoError(t, r.Error)
+			test.wantErr(t, r.Error)
 			assert.Equal(t, test.want, got)
 		})
 	}
diff --git a/reader_test.go b/reader_test.go
index 2724675..de39a64 100644
--- a/reader_test.go
+++ b/reader_test.go
@@ -3,6 +3,7 @@ package avro_test
 import (
 	"bytes"
 	"errors"
+	"strconv"
 	"testing"
 
 	"github.com/hamba/avro"
@@ -66,19 +67,19 @@ func TestReader_Read(t *testing.T) {
 		name    string
 		data    []byte
 		want    []byte
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			name:    "valid",
 			data:    []byte{0xAC, 0xDC, 0x01, 0x00, 0x10, 0x0F},
-			want:    make([]byte, 6),
-			wantErr: false,
+			want:    []byte{0xAC, 0xDC, 0x01, 0x00, 0x10, 0x0F},
+			wantErr: require.NoError,
 		},
 		{
 			name:    "eof",
 			data:    []byte{0xAC}, // io.EOF
-			want:    make([]byte, 6),
-			wantErr: true,
+			want:    []byte{0xAC, 0x00, 0x00, 0x00, 0x00, 0x00},
+			wantErr: require.Error,
 		},
 	}
 
@@ -87,15 +88,11 @@ func TestReader_Read(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			r := avro.NewReader(bytes.NewReader(test.data), 2)
 
-			r.Read(test.want)
-
-			if test.wantErr {
-				assert.Error(t, r.Error)
-				return
-			}
+			got := make([]byte, 6)
+			r.Read(got)
 
-			require.NoError(t, r.Error)
-			assert.Equal(t, test.want, test.data)
+			test.wantErr(t, r.Error)
+			assert.Equal(t, test.want, got)
 		})
 	}
 }
@@ -105,31 +102,31 @@ func TestReader_ReadBool(t *testing.T) {
 		name    string
 		data    []byte
 		want    bool
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			name:    "false",
 			data:    []byte{0x00},
 			want:    false,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "true",
 			data:    []byte{0x01},
 			want:    true,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "invalid bool",
 			data:    []byte{0x02},
 			want:    false,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "eof",
 			data:    []byte(nil), // io.EOF
 			want:    false,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
@@ -141,12 +138,7 @@ func TestReader_ReadBool(t *testing.T) {
 
 			got := r.ReadBool()
 
-			if test.wantErr {
-				assert.Error(t, r.Error)
-				return
-			}
-
-			require.NoError(t, r.Error)
+			test.wantErr(t, r.Error)
 			assert.Equal(t, test.want, got)
 		})
 	}
@@ -157,73 +149,73 @@ func TestReader_ReadInt(t *testing.T) {
 		name    string
 		data    []byte
 		want    int32
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			name:    "positive int",
 			data:    []byte{0x36},
 			want:    27,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "negative int",
 			data:    []byte{0x0F},
 			want:    -8,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "negative int",
 			data:    []byte{0x01},
 			want:    -1,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "zero",
 			data:    []byte{0x00},
 			want:    0,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "one",
 			data:    []byte{0x02},
 			want:    1,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "negative 64",
 			data:    []byte{0x7F},
 			want:    -64,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "multi byte int",
 			data:    []byte{0x80, 0x01},
 			want:    64,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "large int",
 			data:    []byte{0xAA, 0xB4, 0xDE, 0x75},
 			want:    123456789,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "larger int",
 			data:    []byte{0xE2, 0xA2, 0xF3, 0xAD, 0x07},
 			want:    987654321,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "overflow",
 			data:    []byte{0xE2, 0xA2, 0xF3, 0xAD, 0xAD, 0xAD},
 			want:    0,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "eof",
 			data:    []byte{0xE2},
-			want:    0,
-			wantErr: true,
+			want:    49,
+			wantErr: require.Error,
 		},
 	}
 
@@ -235,12 +227,7 @@ func TestReader_ReadInt(t *testing.T) {
 
 			got := r.ReadInt()
 
-			if test.wantErr {
-				assert.Error(t, r.Error)
-				return
-			}
-
-			require.NoError(t, r.Error)
+			test.wantErr(t, r.Error)
 			assert.Equal(t, test.want, got)
 		})
 	}
@@ -250,92 +237,90 @@ func TestReader_ReadLong(t *testing.T) {
 	tests := []struct {
 		data    []byte
 		want    int64
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			data:    []byte{0x36},
 			want:    27,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x0F},
 			want:    -8,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x01},
 			want:    -1,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x00},
 			want:    0,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x02},
 			want:    1,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x7F},
 			want:    -64,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x80, 0x01},
 			want:    64,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xAA, 0xB4, 0xDE, 0x75},
 			want:    123456789,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xE2, 0xA2, 0xF3, 0xAD, 0x07},
 			want:    987654321,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01},
 			want:    9223372036854775807,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01},
 			want:    -9223372036854775808,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xBD, 0xB1, 0xAE, 0xD4, 0xD2, 0xCD, 0xBD, 0xE4, 0x97, 0x01},
 			want:    -5468631321897454687,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xE2, 0xA2, 0xF3, 0xAD, 0xAD, 0xAD, 0xE2, 0xA2, 0xF3, 0xAD, 0xAD}, // Overflow
 			want:    0,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			data:    []byte{0xE2}, // io.EOF
-			want:    0,
-			wantErr: true,
+			want:    49,
+			wantErr: require.Error,
 		},
 	}
 
-	for _, test := range tests {
-		r := avro.NewReader(bytes.NewReader(test.data), 10)
-
-		got := r.ReadLong()
+	for i, test := range tests {
+		test := test
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			r := avro.NewReader(bytes.NewReader(test.data), 10)
 
-		if test.wantErr {
-			assert.Error(t, r.Error)
-			continue
-		}
+			got := r.ReadLong()
 
-		require.NoError(t, r.Error)
-		assert.Equal(t, test.want, got)
+			test.wantErr(t, r.Error)
+			assert.Equal(t, test.want, got)
+		})
 	}
 }
 
@@ -343,56 +328,52 @@ func TestReader_ReadFloat(t *testing.T) {
 	tests := []struct {
 		data    []byte
 		want    float32
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			data:    []byte{0x00, 0x00, 0x00, 0x00},
 			want:    0.0,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x00, 0x00, 0x80, 0x3F},
 			want:    1.0,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x33, 0x33, 0x93, 0x3F},
 			want:    1.15,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x23, 0xDB, 0x57, 0xC2},
 			want:    -53.964,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xA3, 0x79, 0xEB, 0xCC},
 			want:    -123456789.123,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x62, 0x20, 0x71, 0x49},
 			want:    987654.111115,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte(nil), // io.EOF
 			want:    0,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
 	for _, test := range tests {
+		test := test
 		r := avro.NewReader(bytes.NewReader(test.data), 2)
 
 		got := r.ReadFloat()
 
-		if test.wantErr {
-			assert.Error(t, r.Error)
-			continue
-		}
-
-		require.NoError(t, r.Error)
+		test.wantErr(t, r.Error)
 		assert.Equal(t, test.want, got)
 	}
 }
@@ -401,62 +382,62 @@ func TestReader_ReadDouble(t *testing.T) {
 	tests := []struct {
 		data    []byte
 		want    float64
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			data:    []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
 			want:    0.0,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F},
 			want:    1.0,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF2, 0x3F},
 			want:    1.15,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x08, 0xAC, 0x1C, 0x5A, 0x64, 0xFB, 0x4A, 0xC0},
 			want:    -53.964,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xB6, 0xF3, 0x7D, 0x54, 0x34, 0x6F, 0x9D, 0xC1},
 			want:    -123456789.123,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0xB6, 0x10, 0xE4, 0x38, 0x0C, 0x24, 0x2E, 0x41},
 			want:    987654.111115,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x75, 0x6B, 0x7E, 0x54, 0x34, 0x6F, 0x9D, 0x41},
 			want:    123456789.123456789,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x00, 0x00, 0x00, 0x00, 0xD0, 0x12, 0x63, 0x41},
 			want:    9999999.99999999999999999999999,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x18, 0xFC, 0x1A, 0xDD, 0x1F, 0x0E, 0x0A, 0x43},
 			want:    916734926348163.01973408746523,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x0A, 0x8F, 0xA6, 0x40, 0xAC, 0xAD, 0x8D, 0xC3},
 			want:    -267319348967891263.1928357138913857,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte(nil), // io.EOF
 			want:    0,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
@@ -465,12 +446,7 @@ func TestReader_ReadDouble(t *testing.T) {
 
 		got := r.ReadDouble()
 
-		if test.wantErr {
-			assert.Error(t, r.Error)
-			continue
-		}
-
-		require.NoError(t, r.Error)
+		test.wantErr(t, r.Error)
 		assert.Equal(t, test.want, got)
 	}
 }
@@ -479,57 +455,55 @@ func TestReader_ReadBytes(t *testing.T) {
 	tests := []struct {
 		data    []byte
 		want    []byte
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			data:    []byte{0x02, 0x02},
 			want:    []byte{0x02},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x04, 0x03, 0xFF},
 			want:    []byte{0x03, 0xFF},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x08, 0xEC, 0xAB, 0x44, 0x00},
 			want:    []byte{0xEC, 0xAB, 0x44, 0x00},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x0C, 0xAC, 0xDC, 0x01, 0x00, 0x10, 0x0F},
 			want:    []byte{0xAC, 0xDC, 0x01, 0x00, 0x10, 0x0F},
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte(nil), // io.EOF no length
-			want:    nil,
-			wantErr: true,
+			want:    []byte{},
+			wantErr: require.Error,
 		},
 		{
 			data:    []byte{0x05, 0x03, 0xFF, 0x0A}, // Invalid bytes length
 			want:    nil,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			data:    []byte{0x08, 0xFF}, // io.EOF length greater then data
-			want:    nil,
-			wantErr: true,
+			want:    []byte{0xFF, 0x0, 0x0, 0x0},
+			wantErr: require.Error,
 		},
 	}
 
-	for _, test := range tests {
-		r := avro.NewReader(bytes.NewReader(test.data), 10)
-
-		got := r.ReadBytes()
+	for i, test := range tests {
+		test := test
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			r := avro.NewReader(bytes.NewReader(test.data), 10)
 
-		if test.wantErr {
-			assert.Error(t, r.Error)
-			continue
-		}
+			got := r.ReadBytes()
 
-		require.NoError(t, r.Error)
-		assert.Equal(t, test.want, got)
+			test.wantErr(t, r.Error)
+			assert.Equal(t, test.want, got)
+		})
 	}
 }
 
@@ -537,77 +511,75 @@ func TestReader_ReadString(t *testing.T) {
 	tests := []struct {
 		data    []byte
 		want    string
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			data:    []byte{0x00},
 			want:    "",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x06, 0x66, 0x6F, 0x6F},
 			want:    "foo",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x08, 0x61, 0x76, 0x72, 0x6F},
 			want:    "avro",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x0C, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65},
 			want:    "apache",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x28, 0x6F, 0x70, 0x70, 0x61, 0x6E, 0x20, 0x67, 0x61, 0x6E, 0x67, 0x6E, 0x61, 0x6D, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x21},
 			want:    "oppan gangnam style!",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x36, 0xD1, 0x87, 0xD0, 0xB5, 0x2D, 0xD1, 0x82, 0xD0, 0xBE, 0x20, 0xD0, 0xBF, 0xD0, 0xBE, 0x20, 0xD1, 0x80, 0xD1, 0x83, 0xD1, 0x81, 0xD1, 0x81, 0xD0, 0xBA, 0xD0, 0xB8},
 			want:    "че-то по русски",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x0C, 0xE4, 0xB8, 0x96, 0xE7, 0x95, 0x8C},
 			want:    "世界",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte{0x22, 0x21, 0xE2, 0x84, 0x96, 0x3B, 0x25, 0x3A, 0x3F, 0x2A, 0x22, 0x28, 0x29, 0x40, 0x23, 0x24, 0x5E, 0x26},
 			want:    "!№;%:?*\"()@#$^&",
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			data:    []byte(nil), // io.EOF no length
 			want:    "",
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			data:    []byte{0x05, 0x66, 0x6F, 0x6F, 0x6F}, // Invalid string length
 			want:    "",
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			data:    []byte{0x08, 0x66}, // io.EOF length greater then data
-			want:    "",
-			wantErr: true,
+			want:    "\x66\x00\x00\x00",
+			wantErr: require.Error,
 		},
 	}
 
-	for _, test := range tests {
-		r := avro.NewReader(bytes.NewReader(test.data), 10)
-
-		got := r.ReadString()
+	for i, test := range tests {
+		test := test
+		t.Run(strconv.Itoa(i), func(t *testing.T) {
+			r := avro.NewReader(bytes.NewReader(test.data), 10)
 
-		if test.wantErr {
-			assert.Error(t, r.Error)
-			continue
-		}
+			got := r.ReadString()
 
-		require.NoError(t, r.Error)
-		assert.Equal(t, test.want, got)
+			test.wantErr(t, r.Error)
+			assert.Equal(t, test.want, got)
+		})
 	}
 }
 
diff --git a/schema_test.go b/schema_test.go
index 4c3ae54..66c2768 100644
--- a/schema_test.go
+++ b/schema_test.go
@@ -179,77 +179,77 @@ func TestRecordSchema(t *testing.T) {
 	tests := []struct {
 		name    string
 		schema  string
-		wantErr bool
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			name:    "Valid",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "doc": "docs", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: false,
+			wantErr: require.NoError,
 		},
 		{
 			name:    "Invalid Name First Char",
 			schema:  `{"type":"record", "name":"0test", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Name Other Char",
 			schema:  `{"type":"record", "name":"test+", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Name",
 			schema:  `{"type":"record", "name":"", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Name",
 			schema:  `{"type":"record", "namespace": "org.hamba.avro", "fields":[{"name": "intField", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Namespace",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro+", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Namespace",
 			schema:  `{"type":"record", "name":"test", "namespace": "", "fields":[{"name": "intField", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Fields",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Field Type",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":["test"]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Field Name",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Field Name",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "field+", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Alias",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "field", "aliases": ["test+"], "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Field Type",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "field"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Field Type",
 			schema:  `{"type":"record", "name":"test", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "blah"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
@@ -258,57 +258,56 @@ func TestRecordSchema(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			s, err := avro.Parse(test.schema)
 
-			if test.wantErr {
-				assert.Error(t, err)
-				return
+			test.wantErr(t, err)
+			if s != nil {
+				assert.Equal(t, avro.Record, s.Type())
 			}
-
-			require.NoError(t, err)
-			assert.Equal(t, avro.Record, s.Type())
 		})
 	}
 }
 
 func TestErrorRecordSchema(t *testing.T) {
 	tests := []struct {
-		name    string
-		schema  string
-		wantErr bool
+		name       string
+		schema     string
+		wantSchema bool
+		wantErr    require.ErrorAssertionFunc
 	}{
 		{
-			name:    "Valid",
-			schema:  `{"type":"error", "name":"test", "namespace": "org.hamba.avro", "doc": "docs", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: false,
+			name:       "Valid",
+			schema:     `{"type":"error", "name":"test", "namespace": "org.hamba.avro", "doc": "docs", "fields":[{"name": "field", "type": "int"}]}`,
+			wantSchema: true,
+			wantErr:    require.NoError,
 		},
 		{
 			name:    "Invalid Name First Char",
 			schema:  `{"type":"error", "name":"0test", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Name Other Char",
 			schema:  `{"type":"error", "name":"test+", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Name",
 			schema:  `{"type":"error", "name":"", "namespace": "org.hamba.avro", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Name",
 			schema:  `{"type":"error", "namespace": "org.hamba.avro", "fields":[{"name": "intField", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Namespace",
 			schema:  `{"type":"error", "name":"test", "namespace": "org.hamba.avro+", "fields":[{"name": "field", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Namespace",
 			schema:  `{"type":"error", "name":"test", "namespace": "", "fields":[{"name": "intField", "type": "int"}]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
@@ -318,15 +317,12 @@ func TestErrorRecordSchema(t *testing.T) {
 
 			s, err := avro.Parse(test.schema)
 
-			if test.wantErr {
-				assert.Error(t, err)
-				return
+			test.wantErr(t, err)
+			if test.wantSchema {
+				assert.Equal(t, avro.Record, s.Type())
+				recSchema := s.(*avro.RecordSchema)
+				assert.True(t, recSchema.IsError())
 			}
-
-			require.NoError(t, err)
-			assert.Equal(t, avro.Record, s.Type())
-			recSchema := s.(*avro.RecordSchema)
-			assert.True(t, recSchema.IsError())
 		})
 	}
 }
@@ -483,7 +479,7 @@ func TestRecordSchema_ValidatesOrder(t *testing.T) {
 			s, err := avro.Parse(test.schema)
 
 			test.wantErr(t, err)
-			if s != nil {
+			if test.want != "" {
 				rs := s.(*avro.RecordSchema)
 				require.Len(t, rs.Fields(), 1)
 				assert.Equal(t, test.want, rs.Fields()[0].Order())
@@ -567,70 +563,70 @@ func TestEnumSchema(t *testing.T) {
 		schema      string
 		wantName    string
 		wantDefault string
-		wantErr     bool
+		wantErr     require.ErrorAssertionFunc
 	}{
 		{
 			name:     "Valid",
 			schema:   `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
 			wantName: "org.hamba.avro.test",
-			wantErr:  false,
+			wantErr:  require.NoError,
 		},
 		{
 			name:        "Valid With Default",
 			schema:      `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST"], "default": "TEST"}`,
 			wantName:    "org.hamba.avro.test",
 			wantDefault: "TEST",
-			wantErr:     false,
+			wantErr:     require.NoError,
 		},
 		{
 			name:    "Invalid Name",
 			schema:  `{"type":"enum", "name":"test+", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Name",
 			schema:  `{"type":"enum", "name":"", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Name",
 			schema:  `{"type":"enum", "namespace": "org.hamba.avro", "symbols":["TEST"]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Namespace",
 			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro+", "symbols":["TEST"]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Namespace",
 			schema:  `{"type":"enum", "name":"test", "namespace": "", "symbols":["TEST"]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Symbols",
 			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Symbols",
 			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":[]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Symbol",
 			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST+"]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Symbol Type",
 			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":[1]}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Default",
 			schema:  `{"type":"enum", "name":"test", "namespace": "org.hamba.avro", "symbols":["TEST"], "default": "foo"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
@@ -639,16 +635,13 @@ func TestEnumSchema(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			schema, err := avro.Parse(test.schema)
 
-			if test.wantErr {
-				assert.Error(t, err)
-				return
+			test.wantErr(t, err)
+			if test.wantName != "" {
+				assert.Equal(t, avro.Enum, schema.Type())
+				named := schema.(*avro.EnumSchema)
+				assert.Equal(t, test.wantName, named.FullName())
+				assert.Equal(t, test.wantDefault, named.Default())
 			}
-
-			require.NoError(t, err)
-			assert.Equal(t, avro.Enum, schema.Type())
-			named := schema.(*avro.EnumSchema)
-			assert.Equal(t, test.wantName, named.FullName())
-			assert.Equal(t, test.wantDefault, named.Default())
 		})
 	}
 }
@@ -669,37 +662,34 @@ func TestArraySchema(t *testing.T) {
 	tests := []struct {
 		name    string
 		schema  string
-		wantErr bool
+		want    avro.Schema
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			name:    "Valid",
 			schema:  `{"type":"array", "items": "int"}`,
-			wantErr: false,
+			want:    avro.NewArraySchema(avro.NewPrimitiveSchema(avro.Int, nil)),
+			wantErr: require.NoError,
 		},
 		{
 			name:    "No Items",
 			schema:  `{"type":"array"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Items Type",
 			schema:  `{"type":"array", "items": "blah"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
 	for _, test := range tests {
 		test := test
 		t.Run(test.name, func(t *testing.T) {
-			s, err := avro.Parse(test.schema)
-
-			if test.wantErr {
-				assert.Error(t, err)
-				return
-			}
+			got, err := avro.Parse(test.schema)
 
-			require.NoError(t, err)
-			assert.Equal(t, avro.Array, s.Type())
+			test.wantErr(t, err)
+			assert.Equal(t, test.want, got)
 		})
 	}
 }
@@ -718,37 +708,34 @@ func TestMapSchema(t *testing.T) {
 	tests := []struct {
 		name    string
 		schema  string
-		wantErr bool
+		want    avro.Schema
+		wantErr require.ErrorAssertionFunc
 	}{
 		{
 			name:    "Valid",
 			schema:  `{"type":"map", "values": "int"}`,
-			wantErr: false,
+			want:    avro.NewMapSchema(avro.NewPrimitiveSchema(avro.Int, nil)),
+			wantErr: require.NoError,
 		},
 		{
 			name:    "No Values",
 			schema:  `{"type":"map"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Values Type",
 			schema:  `{"type":"map", "values": "blah"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
 	for _, test := range tests {
 		test := test
 		t.Run(test.name, func(t *testing.T) {
-			s, err := avro.Parse(test.schema)
+			got, err := avro.Parse(test.schema)
 
-			if test.wantErr {
-				assert.Error(t, err)
-				return
-			}
-
-			require.NoError(t, err)
-			assert.Equal(t, avro.Map, s.Type())
+			test.wantErr(t, err)
+			assert.Equal(t, test.want, got)
 		})
 	}
 }
@@ -768,45 +755,45 @@ func TestUnionSchema(t *testing.T) {
 		name            string
 		schema          string
 		wantFingerprint [32]byte
-		wantErr         bool
+		wantErr         require.ErrorAssertionFunc
 	}{
 		{
 			name:            "Valid Simple",
 			schema:          `["null", "int"]`,
 			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},
-			wantErr:         false,
+			wantErr:         require.NoError,
 		},
 		{
 			name:            "Valid Complex",
 			schema:          `{"type":["null", "int"]}`,
 			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},
-			wantErr:         false,
+			wantErr:         require.NoError,
 		},
 		{
 			name:            "Dereferences Ref Schemas",
 			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"]}]}]`,
 			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},
-			wantErr:         false,
+			wantErr:         require.NoError,
 		},
 		{
 			name:    "No Nested Union Type",
 			schema:  `["null", ["string"]]`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Duplicate Types",
 			schema:  `["string", "string"]`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Duplicate Names",
 			schema:  `[{"type":"enum", "name":"test", "symbols":["TEST"]}, {"type":"enum", "name":"test", "symbols":["TEST"]}]`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Type",
 			schema:  `["null", "blah"]`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
@@ -815,14 +802,11 @@ func TestUnionSchema(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			s, err := avro.Parse(test.schema)
 
-			if test.wantErr {
-				assert.Error(t, err)
-				return
+			test.wantErr(t, err)
+			if test.wantFingerprint != [32]byte{} {
+				assert.Equal(t, avro.Union, s.Type())
+				assert.Equal(t, test.wantFingerprint, s.Fingerprint())
 			}
-
-			require.NoError(t, err)
-			assert.Equal(t, avro.Union, s.Type())
-			assert.Equal(t, test.wantFingerprint, s.Fingerprint())
 		})
 	}
 }
@@ -869,49 +853,49 @@ func TestFixedSchema(t *testing.T) {
 		schema          string
 		wantName        string
 		wantFingerprint [32]byte
-		wantErr         bool
+		wantErr         require.ErrorAssertionFunc
 	}{
 		{
 			name:            "Valid",
 			schema:          `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": 12}`,
 			wantName:        "org.hamba.avro.test",
 			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},
-			wantErr:         false,
+			wantErr:         require.NoError,
 		},
 		{
 			name:    "Invalid Name",
 			schema:  `{"type":"fixed", "name":"test+", "namespace": "org.hamba.avro", "size": 12}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Name",
 			schema:  `{"type":"fixed", "name":"", "namespace": "org.hamba.avro", "size": 12}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Name",
 			schema:  `{"type":"fixed", "namespace": "org.hamba.avro", "size": 12}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Namespace",
 			schema:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro+", "size": 12}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Empty Namespace",
 			schema:  `{"type":"fixed", "name":"test", "namespace": "", "size": 12}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "No Size",
 			schema:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 		{
 			name:    "Invalid Size Type",
 			schema:  `{"type":"fixed", "name":"test", "namespace": "org.hamba.avro", "size": "test"}`,
-			wantErr: true,
+			wantErr: require.Error,
 		},
 	}
 
@@ -920,16 +904,13 @@ func TestFixedSchema(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			schema, err := avro.Parse(test.schema)
 
-			if test.wantErr {
-				assert.Error(t, err)
-				return
+			test.wantErr(t, err)
+			if test.wantFingerprint != [32]byte{} {
+				assert.Equal(t, avro.Fixed, schema.Type())
+				named := schema.(avro.NamedSchema)
+				assert.Equal(t, test.wantName, named.FullName())
+				assert.Equal(t, test.wantFingerprint, named.Fingerprint())
 			}
-
-			require.NoError(t, err)
-			assert.Equal(t, avro.Fixed, schema.Type())
-			named := schema.(avro.NamedSchema)
-			assert.Equal(t, test.wantName, named.FullName())
-			assert.Equal(t, test.wantFingerprint, named.Fingerprint())
 		})
 	}
 }