func generatePreamble(packagename string, imports []*ast.ImportSpec) string {
	preamble := "package " + packagename + "\n\n"
	for _, iport := range imports {
		preamble = preamble + generateImport(iport) + "\n"
	}
	return preamble + "\n"
}
Generates the header for a complete source file: the package name
and the imports. These imports may be both overzealous (all imports
from the source file are copied across) and incomplete (imports the
generated functions pull in aren't added), so the FixImports
function must be called after the full code has been generated to
fix this up.
package main
import (
	"bytes"
	"errors"
	"fmt"
	"go/ast"
	"strconv"
	"strings"
	"text/template"
	"unicode"
	goimports "golang.org/x/tools/imports"
)
type CodeGenOptions struct {
	Filename string
	PackageName string
	Complete bool
	NoTestCase bool
	NoDefaultFuzz bool
}
type Fuzzer struct {
	Name    string
	Methods []Function
	Wanted  WantedFuzzer
}
var (
	defaultGenerators = map[string]string{
		"bool":       "rand.Intn(2) == 0",
		"byte":       "byte(rand.Uint32())",
		"complex64":  "complex(float32(rand.NormFloat64()), float32(rand.NormFloat64()))",
		"complex128": "complex(rand.NormFloat64(), rand.NormFloat64())",
		"float32":    "float32(rand.NormFloat64())",
		"float64":    "rand.NormFloat64()",
		"int":        "rand.Int()",
		"int8":       "int8(rand.Int())",
		"int16":      "int16(rand.Int())",
		"int32":      "rand.Int31()",
		"int64":      "rand.Int63()",
		"rune":       "rune(rand.Int31())",
		"uint":       "uint(rand.Uint32())",
		"uint8":      "uint8(rand.Uint32())",
		"uint16":     "uint16(rand.Uint32())",
		"uint32":     "rand.Uint32()",
		"uint64":     "(uint64(rand.Uint32()) << 32) | uint64(rand.Uint32())",
	}
	defaultComparisons = map[string]string{
		"error": "((%s == nil) == (%s == nil))",
	}
	fallbackComparison = "reflect.DeepEqual(%s, %s)"
)
const (
	testCaseTemplate = `
{{$name := .Name}}
{{$args := argV .Wanted.Reference.Parameters}}
func FuzzTest{{$name}}(makeTest func({{$args}}) {{$name}}, t *testing.T) {
	rand := rand.New(rand.NewSource(0))
	err := Fuzz{{$name}}(makeTest, rand, 100)
	if err != nil {
		t.Error(err)
	}
}`
	withDefaultReferenceTemplate = `
{{$name  := .Name}}
{{$args  := argV .Wanted.Reference.Parameters}}
{{$decls := makeFunCalls . .Wanted.Reference .Wanted.Reference.Name "makeTest"}}
{{$and   := eitherOr .Wanted.ReturnsValue "&" ""}}
func Fuzz{{$name}}(makeTest func ({{$args}}) {{$name}}, rand *rand.Rand, max uint) error {
{{indent $decls "\t"}}
	return Fuzz{{$name}}With({{$and}}expected{{$name}}, actual{{$name}}, rand, max)
}`
	withReferenceTemplate = `
{{$fuzzer := .}}
{{$name   := .Name}}
{{$count  := len .Methods}}
{{$state  := .Wanted.GeneratorState}}
func Fuzz{{$name}}With(reference {{$name}}, test {{$name}}, rand *rand.Rand, maxops uint) error {
{{if $state | eq ""}}{{else}}	 
	state := {{$state}}
{{end}}	for i := uint(0); i < maxops; i++ {
		actionToPerform := rand.Intn({{$count}})
		switch actionToPerform { {{range $i, $function := .Methods}}
		case {{$i}}:
{{indent (makeFunCalls $fuzzer $function (printf "reference.%s" $function.Name) (printf "test.%s" $function.Name)) "\t\t\t"}}
			if !{{printf (comparison $fuzzer $ty) $expected $actual}} {
				return fmt.Errorf("inconsistent result in {{$function.Name}}\nexpected: %v\nactual:   %v", {{$expected}}, {{$actual}})
			}{{end}}{{end}}
		} {{range $i, $invariant := .Wanted.Invariants}}
		if !({{sed $invariant "%var" "reference"}}) {
			return errors.New("invariant violated: {{$invariant}}")
		}
{{end}}
	}
	return nil
}`
	functionCallTemplate = `
{{$fuzzer       := . }}
{{$function     := function ""}}
{{$expecteds    := expecteds $function}}
{{$actuals      := actuals $function}}
{{$arguments    := arguments $function}}
{{$expectedFunc := expectedFunc ""}}
{{$actualFunc   := actualFunc ""}}
{{if len $arguments | ne 0}}
var ({{range $i, $ty := $function.Parameters}}
	{{argument $function $i}} {{toString $ty}}{{end}}
)
{{range $i, $ty := $function.Parameters}}
{{makeTyGen $fuzzer (argument $function $i) $ty}}{{end}}{{end}}
{{if len $expecteds | eq 0}}
{{$expectedFunc}}({{varV $arguments}})
{{$actualFunc}}({{varV $arguments}})
{{else}}
{{varV $expecteds}} := {{$expectedFunc}}({{varV $arguments}})
{{varV $actuals}} := {{$actualFunc}}({{varV $arguments}})
{{end}}`
)
func CodeGen(options CodeGenOptions, imports []*ast.ImportSpec, fuzzers []Fuzzer) (string, []error) {
	var code string
	var errs []error
	if options.Complete {
		code = generatePreamble(options.PackageName, imports)
	}
	codeGenErr := func(fuzzer Fuzzer, err error) error {
		return fmt.Errorf("error occurred whilst generating code for '%s': %s", fuzzer.Name, err)
	}
	for _, fuzzer := range fuzzers {
		code = code + "// " + fuzzer.Name + "\n\n"
		if !(options.NoTestCase || options.NoDefaultFuzz) {
			generated, err := CodegenTestCase(fuzzer)
			if err != nil {
				errs = append(errs, codeGenErr(fuzzer, err))
				continue
			}
			code = code + generated + "\n\n"
		}
		if !options.NoDefaultFuzz {
			generated, err := CodegenWithDefaultReference(fuzzer)
			if err != nil {
				errs = append(errs, codeGenErr(fuzzer, err))
				continue
			}
			code = code + generated + "\n\n"
		}
		generated, err := CodegenWithReference(fuzzer)
		if err != nil {
			errs = append(errs, codeGenErr(fuzzer, err))
			continue
		}
		code = code + generated + "\n\n"
	}
	code, err := fixImports(options, code)
	if err != nil {
		errs = append(errs, err)
	}
	return code, errs
}