func generateImport(iport *ast.ImportSpec) string {
	if iport.Name != nil {
		return "import " + iport.Name.Name + " " + iport.Path.Value
	}
	return "import " + iport.Path.Value
}
Generates an import statement from an *ast.ImportSpec.
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
}
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"
}