Repository: go-swagger/go-swagger
Pull request #2177 (2020-01-13 13:02:56)

refactored code generator
NO BEHAVIOR CHANGE EXPECTED

* removed some (most) redundant code (left redundancies that would introduce change in behavior to forthcoming PRs)
* factorized spec loading/validating/flattening operations (new spec.go file)
* regrouped state init() function calls
* reduced the number of global vars and replaced them by functions
* adapted template repo to initialize from language options, with adequate template FuncMap
* made DefaultLanguage a configurable function
* moved global golang-specific function to LangueOpts (new language.go file)
* testability: functionalized a number of hard to test code (e.g. all funcmap entries), and introduced unit testing

* started, but did not complete yet the rewriting of unit tests using 'require' instead of nested constructs with 'assert'

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>

codecov[bot]: # [Codecov](https://codecov.io/gh/go-swagger/go-swagger/pull/2177?src=pr&el=h1) Report
> Merging [#2177](https://codecov.io/gh/go-swagger/go-swagger/pull/2177?src=pr&el=desc) into [master](https://codecov.io/gh/go-swagger/go-swagger/commit/f613f6ec23bf9ecbd5612b035eeaf29ce3092f3a?src=pr&el=desc) will **increase** coverage by `0.59%`.
> The diff coverage is `89.67%`.

[![Impacted file tree graph](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/graphs/tree.svg?width=650&token=aQS1DepR8C&height=150&src=pr)](https://codecov.io/gh/go-swagger/go-swagger/pull/2177?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #2177      +/-   ##
==========================================
+ Coverage   80.42%   81.02%   +0.59%     
==========================================
  Files          47       49       +2     
  Lines        8287     8305      +18     
==========================================
+ Hits         6665     6729      +64     
+ Misses       1104     1076      -28     
+ Partials      518      500      -18
```


| [Impacted Files](https://codecov.io/gh/go-swagger/go-swagger/pull/2177?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [generator/debug.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL2RlYnVnLmdv) | `100% <ø> (ø)` | :arrow_up: |
| [generator/operation.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL29wZXJhdGlvbi5nbw==) | `93.34% <100%> (+0.56%)` | :arrow_up: |
| [generator/types.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL3R5cGVzLmdv) | `91.6% <100%> (ø)` | :arrow_up: |
| [generator/client.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL2NsaWVudC5nbw==) | `79.31% <75%> (-0.51%)` | :arrow_down: |
| [generator/spec.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL3NwZWMuZ28=) | `81.18% <81.18%> (ø)` | |
| [generator/language.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL2xhbmd1YWdlLmdv) | `84.02% <84.02%> (ø)` | |
| [generator/model.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL21vZGVsLmdv) | `84.6% <87.5%> (+0.09%)` | :arrow_up: |
| [generator/shared.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL3NoYXJlZC5nbw==) | `88.35% <94%> (+2.86%)` | :arrow_up: |
| [generator/support.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL3N1cHBvcnQuZ28=) | `88.02% <96%> (+6.16%)` | :arrow_up: |
| [generator/template\_repo.go](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree#diff-Z2VuZXJhdG9yL3RlbXBsYXRlX3JlcG8uZ28=) | `93.35% <98.75%> (+5.5%)` | :arrow_up: |
| ... and [4 more](https://codecov.io/gh/go-swagger/go-swagger/pull/2177/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/go-swagger/go-swagger/pull/2177?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/go-swagger/go-swagger/pull/2177?src=pr&el=footer). Last update [f613f6e...a470dfe](https://codecov.io/gh/go-swagger/go-swagger/pull/2177?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/generator/client.go b/generator/client.go
index 7eda6c39..372444f6 100644
--- a/generator/client.go
+++ b/generator/client.go
@@ -15,102 +15,56 @@
 package generator
 
 import (
-	"encoding/json"
 	"errors"
-	"fmt"
-	"os"
 	"path"
-	"path/filepath"
 	"sort"
 
-	"github.com/go-openapi/analysis"
-	"github.com/go-openapi/runtime"
 	"github.com/go-openapi/swag"
 )
 
 // GenerateClient generates a client library for a swagger spec document.
 func GenerateClient(name string, modelNames, operationIDs []string, opts *GenOpts) error {
-	templates.LoadDefaults()
-	if opts == nil {
-		return errors.New("gen opts are required")
-	}
-
-	if opts.Template != "" {
-		if err := templates.LoadContrib(opts.Template); err != nil {
-			return err
-		}
-	}
-
-	templates.SetAllowOverride(opts.AllowTemplateOverride)
-
-	if opts.TemplateDir != "" {
-		if err := templates.LoadDir(opts.TemplateDir); err != nil {
-			return err
-		}
-	}
-
 	if err := opts.CheckOpts(); err != nil {
 		return err
 	}
 
-	// Load the spec
-	_, specDoc, err := loadSpec(opts.Spec)
-	if err != nil {
+	if err := opts.setTemplates(); err != nil {
 		return err
 	}
 
-	// Validate and Expand. specDoc is in/out param.
-	specDoc, err = validateAndFlattenSpec(opts, specDoc)
+	specDoc, analyzed, err := opts.analyzeSpec()
 	if err != nil {
 		return err
 	}
 
-	analyzed := analysis.New(specDoc.Spec())
-
 	models, err := gatherModels(specDoc, modelNames)
 	if err != nil {
 		return err
 	}
 
 	operations := gatherOperations(analyzed, operationIDs)
-
 	if len(operations) == 0 {
 		return errors.New("no operations were selected")
 	}
 
-	defaultScheme := opts.DefaultScheme
-	if defaultScheme == "" {
-		defaultScheme = sHTTP
-	}
-
-	defaultConsumes := opts.DefaultConsumes
-	if defaultConsumes == "" {
-		defaultConsumes = runtime.JSONMime
-	}
-
-	defaultProduces := opts.DefaultProduces
-	if defaultProduces == "" {
-		defaultProduces = runtime.JSONMime
-	}
-
 	generator := appGenerator{
-		Name:              appNameOrDefault(specDoc, name, "rest"),
+		Name:              appNameOrDefault(specDoc, name, defaultClientName),
 		SpecDoc:           specDoc,
 		Analyzed:          analyzed,
 		Models:            models,
 		Operations:        operations,
 		Target:            opts.Target,
 		DumpData:          opts.DumpData,
-		Package:           opts.LanguageOpts.ManglePackageName(opts.ClientPackage, "client"),
-		APIPackage:        opts.LanguageOpts.ManglePackagePath(opts.APIPackage, "api"),
-		ModelsPackage:     opts.LanguageOpts.ManglePackagePath(opts.ModelPackage, "definitions"),
-		ServerPackage:     opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, "server"),
-		ClientPackage:     opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, "client"),
-		OperationsPackage: opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, "client"),
+		Package:           opts.LanguageOpts.ManglePackageName(opts.ClientPackage, defaultClientTarget),
+		APIPackage:        opts.LanguageOpts.ManglePackagePath(opts.APIPackage, defaultOperationsTarget),
+		ModelsPackage:     opts.LanguageOpts.ManglePackagePath(opts.ModelPackage, defaultModelsTarget),
+		ServerPackage:     opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, defaultServerTarget),
+		ClientPackage:     opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, defaultClientTarget),
+		OperationsPackage: opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, defaultClientTarget),
 		Principal:         opts.Principal,
-		DefaultScheme:     defaultScheme,
-		DefaultProduces:   defaultProduces,
-		DefaultConsumes:   defaultConsumes,
+		DefaultScheme:     opts.DefaultScheme,
+		DefaultProduces:   opts.DefaultProduces,
+		DefaultConsumes:   opts.DefaultConsumes,
 		GenOpts:           opts,
 	}
 	generator.Receiver = "o"
@@ -123,6 +77,10 @@ type clientGenerator struct {
 
 func (c *clientGenerator) Generate() error {
 	app, err := c.makeCodegenApp()
+	if err != nil {
+		return err
+	}
+
 	if app.Name == "" {
 		app.Name = "APIClient"
 	}
@@ -132,31 +90,27 @@ func (c *clientGenerator) Generate() error {
 		if app.Imports == nil {
 			app.Imports = make(map[string]string)
 		}
-		pkgAlias := c.GenOpts.LanguageOpts.ManglePackageName(c.ModelsPackage, "models")
+		pkgAlias := c.GenOpts.LanguageOpts.ManglePackageName(c.ModelsPackage, defaultModelsTarget)
 		app.Imports[pkgAlias] = path.Join(
-			filepath.ToSlash(baseImport),
-			c.GenOpts.LanguageOpts.ManglePackagePath(c.GenOpts.ModelPackage, "models"))
+			baseImport,
+			c.GenOpts.LanguageOpts.ManglePackagePath(c.GenOpts.ModelPackage, defaultModelsTarget))
 	} else {
 		app.DefaultImports = append(app.DefaultImports, c.GenOpts.LanguageOpts.ManglePackagePath(c.GenOpts.ExistingModels, ""))
 	}
-	if err != nil {
-		return err
-	}
 
 	if c.DumpData {
-		bb, _ := json.MarshalIndent(swag.ToDynamicJSON(app), "", "  ")
-		fmt.Fprintln(os.Stdout, string(bb))
-		return nil
+		return dumpData(swag.ToDynamicJSON(app))
 	}
 
 	if c.GenOpts.IncludeModel {
 		for _, mod := range app.Models {
 			modCopy := mod
 			modCopy.IncludeValidator = true
-			if !mod.IsStream {
-				if err := c.GenOpts.renderDefinition(&modCopy); err != nil {
-					return err
-				}
+			if mod.IsStream {
+				continue
+			}
+			if err := c.GenOpts.renderDefinition(&modCopy); err != nil {
+				return err
 			}
 		}
 	}
@@ -181,8 +135,8 @@ func (c *clientGenerator) Generate() error {
 			}
 			app.DefaultImports = append(app.DefaultImports,
 				path.Join(
-					filepath.ToSlash(baseImport),
-					c.GenOpts.LanguageOpts.ManglePackagePath(c.ClientPackage, "client"),
+					baseImport,
+					c.GenOpts.LanguageOpts.ManglePackagePath(c.ClientPackage, defaultClientTarget),
 					opGroup.Name))
 
 			if err := c.GenOpts.renderOperationGroup(&opGroup); err != nil {
diff --git a/generator/debug.go b/generator/debug.go
index 050b01f1..61b4b8d4 100644
--- a/generator/debug.go
+++ b/generator/debug.go
@@ -31,10 +31,6 @@ var (
 	generatorLogger *log.Logger
 )
 
-func init() {
-	debugOptions()
-}
-
 func debugOptions() {
 	generatorLogger = log.New(os.Stdout, "generator:", log.LstdFlags)
 }
diff --git a/generator/language.go b/generator/language.go
new file mode 100644
index 00000000..1ff77695
--- /dev/null
+++ b/generator/language.go
@@ -0,0 +1,382 @@
+package generator
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"regexp"
+	goruntime "runtime"
+	"strings"
+
+	"github.com/go-openapi/swag"
+	"golang.org/x/tools/imports"
+)
+
+var (
+	// DefaultLanguageFunc defines the default generation language
+	DefaultLanguageFunc func() *LanguageOpts
+
+	moduleRe *regexp.Regexp
+)
+
+func initLanguage() {
+	DefaultLanguageFunc = GoLangOpts
+
+	moduleRe = regexp.MustCompile(`module[ \t]+([^\s]+)`)
+}
+
+// LanguageOpts to describe a language to the code generator
+type LanguageOpts struct {
+	ReservedWords        []string
+	BaseImportFunc       func(string) string               `json:"-"`
+	ArrayInitializerFunc func(interface{}) (string, error) `json:"-"`
+	reservedWordsSet     map[string]struct{}
+	initialized          bool
+	formatFunc           func(string, []byte) ([]byte, error)
+	fileNameFunc         func(string) string // language specific source file naming rules
+}
+
+// Init the language option
+func (l *LanguageOpts) Init() {
+	if l.initialized {
+		return
+	}
+	l.initialized = true
+	l.reservedWordsSet = make(map[string]struct{})
+	for _, rw := range l.ReservedWords {
+		l.reservedWordsSet[rw] = struct{}{}
+	}
+}
+
+// MangleName makes sure a reserved word gets a safe name
+func (l *LanguageOpts) MangleName(name, suffix string) string {
+	if _, ok := l.reservedWordsSet[swag.ToFileName(name)]; !ok {
+		return name
+	}
+	return strings.Join([]string{name, suffix}, "_")
+}
+
+// MangleVarName makes sure a reserved word gets a safe name
+func (l *LanguageOpts) MangleVarName(name string) string {
+	nm := swag.ToVarName(name)
+	if _, ok := l.reservedWordsSet[nm]; !ok {
+		return nm
+	}
+	return nm + "Var"
+}
+
+// MangleFileName makes sure a file name gets a safe name
+func (l *LanguageOpts) MangleFileName(name string) string {
+	if l.fileNameFunc != nil {
+		return l.fileNameFunc(name)
+	}
+	return swag.ToFileName(name)
+}
+
+// ManglePackageName makes sure a package gets a safe name.
+// In case of a file system path (e.g. name contains "/" or "\" on Windows), this return only the last element.
+func (l *LanguageOpts) ManglePackageName(name, suffix string) string {
+	if name == "" {
+		return suffix
+	}
+	pth := filepath.ToSlash(filepath.Clean(name)) // preserve path
+	_, pkg := path.Split(pth)                     // drop path
+	return l.MangleName(swag.ToFileName(pkg), suffix)
+}
+
+// ManglePackagePath makes sure a full package path gets a safe name.
+// Only the last part of the path is altered.
+func (l *LanguageOpts) ManglePackagePath(name string, suffix string) string {
+	if name == "" {
+		return suffix
+	}
+	target := filepath.ToSlash(filepath.Clean(name)) // preserve path
+	parts := strings.Split(target, "/")
+	parts[len(parts)-1] = l.ManglePackageName(parts[len(parts)-1], suffix)
+	return strings.Join(parts, "/")
+}
+
+// FormatContent formats a file with a language specific formatter
+func (l *LanguageOpts) FormatContent(name string, content []byte) ([]byte, error) {
+	if l.formatFunc != nil {
+		return l.formatFunc(name, content)
+	}
+	return content, nil
+}
+
+func (l *LanguageOpts) baseImport(tgt string) string {
+	if l.BaseImportFunc != nil {
+		return l.BaseImportFunc(tgt)
+	}
+	debugLog("base import func is nil")
+	return ""
+}
+
+// GoLangOpts for rendering items as golang code
+func GoLangOpts() *LanguageOpts {
+	var goOtherReservedSuffixes = map[string]bool{
+		// see:
+		// https://golang.org/src/go/build/syslist.go
+		// https://golang.org/doc/install/source#environment
+
+		// goos
+		"aix":       true,
+		"android":   true,
+		"darwin":    true,
+		"dragonfly": true,
+		"freebsd":   true,
+		"hurd":      true,
+		"illumos":   true,
+		"js":        true,
+		"linux":     true,
+		"nacl":      true,
+		"netbsd":    true,
+		"openbsd":   true,
+		"plan9":     true,
+		"solaris":   true,
+		"windows":   true,
+		"zos":       true,
+
+		// arch
+		"386":         true,
+		"amd64":       true,
+		"amd64p32":    true,
+		"arm":         true,
+		"armbe":       true,
+		"arm64":       true,
+		"arm64be":     true,
+		"mips":        true,
+		"mipsle":      true,
+		"mips64":      true,
+		"mips64le":    true,
+		"mips64p32":   true,
+		"mips64p32le": true,
+		"ppc":         true,
+		"ppc64":       true,
+		"ppc64le":     true,
+		"riscv":       true,
+		"riscv64":     true,
+		"s390":        true,
+		"s390x":       true,
+		"sparc":       true,
+		"sparc64":     true,
+		"wasm":        true,
+
+		// other reserved suffixes
+		"test": true,
+	}
+
+	opts := new(LanguageOpts)
+	opts.ReservedWords = []string{
+		"break", "default", "func", "interface", "select",
+		"case", "defer", "go", "map", "struct",
+		"chan", "else", "goto", "package", "switch",
+		"const", "fallthrough", "if", "range", "type",
+		"continue", "for", "import", "return", "var",
+	}
+
+	opts.formatFunc = func(ffn string, content []byte) ([]byte, error) {
+		opts := new(imports.Options)
+		opts.TabIndent = true
+		opts.TabWidth = 2
+		opts.Fragment = true
+		opts.Comments = true
+		return imports.Process(ffn, content, opts)
+	}
+
+	opts.fileNameFunc = func(name string) string {
+		// whenever a generated file name ends with a suffix
+		// that is meaningful to go build, adds a "swagger"
+		// suffix
+		parts := strings.Split(swag.ToFileName(name), "_")
+		if goOtherReservedSuffixes[parts[len(parts)-1]] {
+			// file name ending with a reserved arch or os name
+			// are appended an innocuous suffix "swagger"
+			parts = append(parts, "swagger")
+		}
+		return strings.Join(parts, "_")
+	}
+
+	opts.ArrayInitializerFunc = func(data interface{}) (string, error) {
+		// ArrayInitializer constructs a Go literal initializer from interface{} literals.
+		// e.g. []interface{}{"a", "b"} is transformed in {"a","b",}
+		// e.g. map[string]interface{}{ "a": "x", "b": "y"} is transformed in {"a":"x","b":"y",}.
+		//
+		// NOTE: this is currently used to construct simple slice intializers for default values.
+		// This allows for nicer slice initializers for slices of primitive types and avoid systematic use for json.Unmarshal().
+		b, err := json.Marshal(data)
+		if err != nil {
+			return "", err
+		}
+		return strings.Replace(strings.Replace(strings.Replace(string(b), "}", ",}", -1), "[", "{", -1), "]", ",}", -1), nil
+	}
+
+	opts.BaseImportFunc = func(tgt string) string {
+		tgt = filepath.Clean(tgt)
+		// On Windows, filepath.Abs("") behaves differently than on Unix.
+		// Windows: yields an error, since Abs() does not know the volume.
+		// UNIX: returns current working directory
+		if tgt == "" {
+			tgt = "."
+		}
+		tgtAbsPath, err := filepath.Abs(tgt)
+		if err != nil {
+			log.Fatalf("could not evaluate base import path with target \"%s\": %v", tgt, err)
+		}
+
+		var tgtAbsPathExtended string
+		tgtAbsPathExtended, err = filepath.EvalSymlinks(tgtAbsPath)
+		if err != nil {
+			log.Fatalf("could not evaluate base import path with target \"%s\" (with symlink resolution): %v", tgtAbsPath, err)
+		}
+
+		gopath := os.Getenv("GOPATH")
+		if gopath == "" {
+			gopath = filepath.Join(os.Getenv("HOME"), "go")
+		}
+
+		var pth string
+		for _, gp := range filepath.SplitList(gopath) {
+			// EvalSymLinks also calls the Clean
+			gopathExtended, er := filepath.EvalSymlinks(gp)
+			if er != nil {
+				log.Fatalln(er)
+			}
+			gopathExtended = filepath.Join(gopathExtended, "src")
+			gp = filepath.Join(gp, "src")
+
+			// At this stage we have expanded and unexpanded target path. GOPATH is fully expanded.
+			// Expanded means symlink free.
+			// We compare both types of targetpath
 with gopath.
+			// If any one of them coincides with gopath , it is imperative that
+			// target path lies inside gopath. How?
+			// 		- Case 1: Irrespective of symlinks paths coincide. Both non-expanded paths.
+			// 		- Case 2: Symlink in target path points to location inside GOPATH. (Expanded Target Path)
+			//    - Case 3: Symlink in target path points to directory outside GOPATH (Unexpanded target path)
+
+			// Case 1: - Do nothing case. If non-expanded paths match just generate base import path as if
+			//				   there are no symlinks.
+
+			// Case 2: - Symlink in target path points to location inside GOPATH. (Expanded Target Path)
+			//					 First if will fail. Second if will succeed.
+
+			// Case 3: - Symlink in target path points to directory outside GOPATH (Unexpanded target path)
+			// 					 First if will succeed and break.
+
+			// compares non expanded path for both
+			if ok, relativepath := checkPrefixAndFetchRelativePath(tgtAbsPath, gp); ok {
+				pth = relativepath
+				break
+			}
+
+			// Compares non-expanded target path
+			if ok, relativepath := checkPrefixAndFetchRelativePath(tgtAbsPath, gopathExtended); ok {
+				pth = relativepath
+				break
+			}
+
+			// Compares expanded target path.
+			if ok, relativepath := checkPrefixAndFetchRelativePath(tgtAbsPathExtended, gopathExtended); ok {
+				pth = relativepath
+				break
+			}
+
+		}
+
+		mod, goModuleAbsPath, err := tryResolveModule(tgtAbsPath)
+		switch {
+		case err != nil:
+			log.Fatalf("Failed to resolve module using go.mod file: %s", err)
+		case mod != "":
+			relTgt := relPathToRelGoPath(goModuleAbsPath, tgtAbsPath)
+			if !strings.HasSuffix(mod, relTgt) {
+				return filepath.ToSlash(mod + relTgt)
+			}
+			return filepath.ToSlash(mod)
+		}
+
+		if pth == "" {
+			log.Fatalln("target must reside inside a location in the $GOPATH/src or be a module")
+		}
+		return filepath.ToSlash(pth)
+	}
+	opts.Init()
+	return opts
+}
+
+// resolveGoModFile walks up the directory tree starting from 'dir' until it
+// finds a go.mod file. If go.mod is found it will return the related file
+// object. If no go.mod file is found it will return an error.
+func resolveGoModFile(dir string) (*os.File, string, error) {
+	goModPath := filepath.Join(dir, "go.mod")
+	f, err := os.Open(goModPath)
+	if err != nil {
+		if os.IsNotExist(err) && dir != filepath.Dir(dir) {
+			return resolveGoModFile(filepath.Dir(dir))
+		}
+		return nil, "", err
+	}
+	return f, dir, nil
+}
+
+// relPathToRelGoPath takes a relative os path and returns the relative go
+// package path. For unix nothing will change but for windows \ will be
+// converted to /.
+func relPathToRelGoPath(modAbsPath, absPath string) string {
+	if absPath == "." {
+		return ""
+	}
+
+	path := strings.TrimPrefix(absPath, modAbsPath)
+	pathItems := strings.Split(path, string(filepath.Separator))
+	return strings.Join(pathItems, "/")
+}
+
+func tryResolveModule(baseTargetPath string) (string, string, error) {
+	f, goModAbsPath, err := resolveGoModFile(baseTargetPath)
+	switch {
+	case os.IsNotExist(err):
+		return "", "", nil
+	case err != nil:
+		return "", "", err
+	}
+
+	src, err := ioutil.ReadAll(f)
+	if err != nil {
+		return "", "", err
+	}
+
+	match := moduleRe.FindSubmatch(src)
+	if len(match) != 2 {
+		return "", "", nil
+	}
+
+	return string(match[1]), goModAbsPath, nil
+}
+
+// 1. Checks if the child path and parent path coincide.
+// 2. If they do return child path  relative to parent path.
+// 3. Everything else return false
+func checkPrefixAndFetchRelativePath(childpath string, parentpath string) (bool, string) {
+	// Windows (local) file systems - NTFS, as well as FAT and variants
+	// are case insensitive.
+	cp, pp := childpath, parentpath
+	if goruntime.GOOS == "windows" {
+		cp = strings.ToLower(cp)
+		pp = strings.ToLower(pp)
+	}
+
+	if strings.HasPrefix(cp, pp) {
+		pth, err := filepath.Rel(parentpath, childpath)
+		if err != nil {
+			log.Fatalln(err)
+		}
+		return true, pth
+	}
+
+	return false, ""
+
+}
diff --git a/generator/model.go b/generator/model.go
index dbaae397..27aa3669 100644
--- a/generator/model.go
+++ b/generator/model.go
@@ -15,11 +15,8 @@
 package generator
 
 import (
-	"encoding/json"
-	"errors"
 	"fmt"
 	"log"
-	"os"
 	"path"
 	"path/filepath"
 	"sort"
@@ -51,24 +48,15 @@ Every action that happens tracks the path which is a linked list of refs
 
 // GenerateDefinition generates a model file for a schema definition.
 func GenerateDefinition(modelNames []string, opts *GenOpts) error {
-	if opts == nil {
-		return errors.New("gen opts are required")
-	}
-
-	templates.SetAllowOverride(opts.AllowTemplateOverride)
-
-	if opts.TemplateDir != "" {
-		if err := templates.LoadDir(opts.TemplateDir); err != nil {
-			return err
-		}
+	if err := opts.CheckOpts(); err != nil {
+		return err
 	}
 
-	if err := opts.CheckOpts(); err != nil {
+	if err := opts.setTemplates(); err != nil {
 		return err
 	}
 
-	// Load the spec
-	specPath, specDoc, err := loadSpec(opts.Spec)
+	specDoc, _, err := opts.analyzeSpec()
 	if err != nil {
 		return err
 	}
@@ -83,7 +71,7 @@ func GenerateDefinition(modelNames []string, opts *GenOpts) error {
 		// lookup schema
 		model, ok := specDoc.Spec().Definitions[modelName]
 		if !ok {
-			return fmt.Errorf("model %q not found in definitions given by %q", modelName, specPath)
+			return fmt.Errorf("model %q not found in definitions given by %q", modelName, opts.Spec)
 		}
 
 		// generate files
@@ -121,9 +109,7 @@ func (m *definitionGenerator) Generate() error {
 	}
 
 	if m.opts.DumpData {
-		bb, _ := json.MarshalIndent(swag.ToDynamicJSON(mod), "", " ")
-		fmt.Fprintln(os.Stdout, string(bb))
-		return nil
+		return dumpData(swag.ToDynamicJSON(mod))
 	}
 
 	if m.opts.IncludeModel {
@@ -346,7 +332,7 @@ func makeGenDefinitionHierarchy(name, pkg, container string, schema spec.Schema,
 	return &GenDefinition{
 		GenCommon: GenCommon{
 			Copyright:        opts.Copyright,
-			TargetImportPath: filepath.ToSlash(opts.LanguageOpts.baseImport(opts.Target)),
+			TargetImportPath: opts.LanguageOpts.baseImport(opts.Target),
 		},
 		Package:        opts.LanguageOpts.ManglePackageName(path.Base(filepath.ToSlash(pkg)), "definitions"),
 		GenSchema:      pg.GenSchema,
@@ -712,7 +698,7 @@ func (sg *schemaGenContext) buildProperties() error {
 			sg.Name, k, sg.IsTuple, sg.GenSchema.HasValidations)
 
 		// check if this requires de-anonymizing, if so lift this as a new struct and extra schema
-		tpe, err := sg.TypeResolver.ResolveSchema(&v, true, sg.IsTuple || containsString(sg.Schema.Required, k))
+		tpe, err := sg.TypeResolver.ResolveSchema(&v, true, sg.IsTuple || swag.ContainsStrings(sg.Schema.Required, k))
 		if sg.Schema.Discriminator == k {
 			tpe.IsNullable = false
 		}
diff --git a/generator/operation.go b/generator/operation.go
index 3ad2dcb4..7920813f 100644
--- a/generator/operation.go
+++ b/generator/operation.go
@@ -18,7 +18,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"os"
 	"path"
 	"path/filepath"
 	"sort"
@@ -59,37 +58,19 @@ func sortedResponses(input map[int]spec.Response) responses {
 // It also generates an operation handler interface that uses the parameter model for handling a valid request.
 // Allows for specifying a list of tags to include only certain tags for the generation
 func GenerateServerOperation(operationNames []string, opts *GenOpts) error {
-	if opts == nil {
-		return errors.New("gen opts are required")
-	}
-	templates.LoadDefaults()
-
-	templates.SetAllowOverride(opts.AllowTemplateOverride)
-
-	if opts.TemplateDir != "" {
-		if err := templates.LoadDir(opts.TemplateDir); err != nil {
-			return err
-		}
-	}
-
 	if err := opts.CheckOpts(); err != nil {
 		return err
 	}
 
-	// Load the spec
-	_, specDoc, err := loadSpec(opts.Spec)
-	if err != nil {
+	if err := opts.setTemplates(); err != nil {
 		return err
 	}
 
-	// Validate and Expand. specDoc is in/out param.
-	specDoc, err = validateAndFlattenSpec(opts, specDoc)
+	specDoc, analyzed, err := opts.analyzeSpec()
 	if err != nil {
 		return err
 	}
 
-	analyzed := analysis.New(specDoc.Spec())
-
 	ops := gatherOperations(analyzed, operationNames)
 	if len(ops) == 0 {
 		return errors.New("no operations were selected")
@@ -97,28 +78,16 @@ func GenerateServerOperation(operationNames []string, opts *GenOpts) error {
 
 	for operationName, opRef := range ops {
 		method, path, operation := opRef.Method, opRef.Path, opRef.Op
-		defaultScheme := opts.DefaultScheme
-		if defaultScheme == "" {
-			defaultScheme = sHTTP
-		}
-		defaultProduces := opts.DefaultProduces
-		if defaultProduces == "" {
-			defaultProduces = runtime.JSONMime
-		}
-		defaultConsumes := opts.DefaultConsumes
-		if defaultConsumes == "" {
-			defaultConsumes = runtime.JSONMime
-		}
 
-		serverPackage := opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, "server")
+		serverPackage := opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, defaultServerTarget)
 		generator := operationGenerator{
 			Name:                 operationName,
 			Method:               method,
 			Path:                 path,
 			BasePath:             specDoc.BasePath(),
-			APIPackage:           opts.LanguageOpts.ManglePackagePath(opts.APIPackage, "api"),
-			ModelsPackage:        opts.LanguageOpts.ManglePackagePath(opts.ModelPackage, "definitions"),
-			ClientPackage:        opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, "client"),
+			APIPackage:           opts.LanguageOpts.ManglePackagePath(opts.APIPackage, defaultOperationsTarget),
+			ModelsPackage:        opts.LanguageOpts.ManglePackagePath(opts.ModelPackage, defaultModelsTarget),
+			ClientPackage:        opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, defaultClientTarget),
 			ServerPackage:        serverPackage,
 			Operation:            *operation,
 			SecurityRequirements: analyzed.SecurityRequirementsFor(operation),
@@ -132,9 +101,9 @@ func GenerateServerOperation(operationNames []string, opts *GenOpts) error {
 			IncludeResponses:     opts.IncludeResponses,
 			IncludeValidator:     true, // we no more support the CLI option to disable validation
 			DumpData:             opts.DumpData,
-			DefaultScheme:        defaultScheme,
-			DefaultProduces:      defaultProduces,
-			DefaultConsumes:      defaultConsumes,
+			DefaultScheme:        opts.DefaultScheme,
+			DefaultProduces:      opts.DefaultProduces,
+			DefaultConsumes:      opts.DefaultConsumes,
 			Doc:                  specDoc,
 			Analyzed:             analyzed,
 			GenOpts:              opts,
@@ -177,19 +146,6 @@ type operationGenerator struct {
 	GenOpts              *GenOpts
 }
 
-func intersectTags(left, right []string) (filtered []string) {
-	if len(right) == 0 {
-		filtered = left
-		return
-	}
-	for _, l := range left {
-		if containsString(right, l) {
-			filtered = append(filtered, l)
-		}
-	}
-	return
-}
-
 func (o *operationGenerator) Generate() error {
 	// Build a list of codegen operations based on the tags,
 	// the tag decides the actual package for an operation
@@ -213,7 +169,7 @@ func (o *operationGenerator) Generate() error {
 	bldr.Analyzed = o.Analyzed
 	bldr.DefaultScheme = o.DefaultScheme
 	bldr.DefaultProduces = o.DefaultProduces
-	bldr.RootAPIPackage = o.GenOpts.LanguageOpts.ManglePackageName(o.ServerPackage, "server")
+	bldr.RootAPIPackage = o.GenOpts.LanguageOpts.ManglePackageName(o.ServerPackage, defaultServerTarget)
 	bldr.GenOpts = o.GenOpts
 	bldr.DefaultConsumes = o.DefaultConsumes
 	bldr.IncludeValidator = o.IncludeValidator
@@ -222,7 +178,7 @@ func (o *operationGenerator) Generate() error {
 	if o.GenOpts.ExistingModels == "" {
 		bldr.DefaultImports = []string{
 			path.Join(
-				filepath.ToSlash(o.GenOpts.LanguageOpts.baseImport(o.Base)),
+				o.GenOpts.LanguageOpts.baseImport(o.Base),
 				o.GenOpts.LanguageOpts.ManglePackagePath(o.ModelsPackage, "")),
 		}
 	}
@@ -247,8 +203,7 @@ func (o *operationGenerator) Generate() error {
 
 	for _, op := range operations {
 		if o.GenOpts.DumpData {
-			bb, _ := json.MarshalIndent(swag.ToDynamicJSON(op), "", " ")
-			fmt.Fprintln(os.Stdout, string(bb))
+			_ = dumpData(swag.ToDynamicJSON(op))
 			continue
 		}
 		if err := o.GenOpts.renderOperation(&op); err != nil {
@@ -287,12 +242,43 @@ type codeGenOpBuilder struct {
 	GenOpts             *GenOpts
 }
 
+// paramMappings yields a map of safe parameter names for an operation
+func paramMappings(params map[string]spec.Parameter) (map[string]map[string]string, string) {
+	idMapping := map[string]map[string]string{
+		"query":    make(map[string]string, len(params)),
+		"path":     make(map[string]string, len(params)),
+		"formData": make(map[string]string, len(params)),
+		"header":   make(map[string]string, len(params)),
+		"body":     make(map[string]string, len(params)),
+	}
+
+	// In order to avoid unstable generation, adopt same naming convention
+	// for all parameters with same name across locations.
+	seenIds := make(map[string]interface{}, len(params))
+	for id, p := range params {
+		if val, ok := seenIds[p.Name]; ok {
+			previous := val.(struct{ id, in string })
+			idMapping[p.In][p.Name] = swag.ToGoName(id)
+			// rewrite the previously found one
+			idMapping[previous.in][p.Name] = swag.ToGoName(previous.id)
+		} else {
+			idMapping[p.In][p.Name] = swag.ToGoName(p.Name)
+		}
+		seenIds[strings.ToLower(idMapping[p.In][p.Name])] = struct{ id, in string }{id: id, in: p.In}
+	}
+
+	// pick a deconflicted private name for timeout for this operation
+	timeoutName := renameTimeout(seenIds, "timeout")
+
+	return idMapping, timeoutName
+}
+
 // renameTimeout renames the variable in use by client template to avoid conflicting
 // with param names.
 //
 // NOTE: this merely protects the timeout field in the client parameter struct,
 // fields "Context" and "HTTPClient" remain exposed to name conflicts.
-func renameTimeout(seenIds map[string]bool, timeoutName string) string {
+func renameTimeout(seenIds map[string]interface{}, timeoutName string) string {
 	if seenIds == nil {
 		return timeoutName
 	}
@@ -333,7 +319,7 @@ func (b *codeGenOpBuilder) MakeOperation() (GenOperation, error) {
 	//
 	// In all cases, resetting definitions to the _original_ (untransformed) spec is not an option:
 	// we take from there the spec possibly already transformed by the GenDefinitions stage.
-	resolver := newTypeResolver(b.GenOpts.LanguageOpts.ManglePackageName(b.ModelsPackage, "models"), b.Doc)
+	resolver := newTypeResolver(b.GenOpts.LanguageOpts.ManglePackageName(b.ModelsPackage, defaultModelsTarget), b.Doc)
 	receiver := "o"
 
 	operation := b.Operation
@@ -341,24 +327,7 @@ func (b *codeGenOpBuilder) MakeOperation() (GenOperation, error) {
 	var hasQueryParams, hasPathParams, hasHeaderParams, hasFormParams, hasFileParams, hasFormValueParams, hasBodyParams bool
 	paramsForOperation := b.Analyzed.ParamsFor(b.Method, b.Path)
 
-	idMapping := map[string]map[string]string{
-		"query":    make(map[string]string, len(paramsForOperation)),
-		"path":     make(map[string]string, len(paramsForOperation)),
-		"formData": make(map[string]string, len(paramsForOperation)),
-		"header":   make(map[string]string, len(paramsForOperation)),
-		"body":     make(map[string]string, len(paramsForOperation)),
-	}
-
-	seenIds := make(map[string]bool, len(paramsForOperation))
-	for id, p := range paramsForOperation {
-		if _, ok := seenIds[p.Name]; ok {
-			idMapping[p.In][p.Name] = swag.ToGoName(id)
-		} else {
-			idMapping[p.In][p.Name] = swag.ToGoName(p.Name)
-		}
-		seenIds[strings.ToLower(idMapping[p.In][p.Name])] = true
-	}
-	timeoutName := renameTimeout(seenIds, "timeout")
+	idMapping, timeoutName := paramMappings(paramsForOperation)
 
 	for _, p := range paramsForOperation {
 		cp, err := b.MakeParameter(receiver, resolver, p, idMapping)
@@ -496,9 +465,9 @@ func (b *codeGenOpBuilder) MakeOperation() (GenOperation, error) {
 	return GenOperation{
 		GenCommon: GenCommon{
 			Copyright:        b.GenOpts.Copyright,
-			TargetImportPath: filepath.ToSlash(b.GenOpts.LanguageOpts.baseImport(b.GenOpts.Target)),
+			TargetImportPath: b.GenOpts.LanguageOpts.baseImport(b.GenOpts.Target),
 		},
-		Package:              b.GenOpts.LanguageOpts.ManglePackageName(b.APIPackage, "api"),
+		Package:              b.GenOpts.LanguageOpts.ManglePackageName(b.APIPackage, defaultOperationsTarget),
 		RootPackage:          b.RootAPIPackage,
 		Name:                 b.Name,
 		Method:               b.Method,
@@ -580,7 +549,7 @@ func (b *codeGenOpBuilder) MakeResponse(receiver, name string, isSuccess bool, r
 	// assume minimal flattening has been carried on, so there is not $ref in response (but some may remain in response schema)
 
 	res := GenResponse{
-		Package:        b.GenOpts.LanguageOpts.ManglePackageName(b.APIPackage, "api"),
+		Package:        b.GenOpts.LanguageOpts.ManglePackageName(b.APIPackage, defaultOperationsTarget),
 		ModelsPackage:  b.ModelsPackage,
 		ReceiverName:   receiver,
 		Name:           name,
@@ -622,7 +591,7 @@ func (b *codeGenOpBuilder) MakeHeader(receiver, name string, hdr spec.Header) (G
 	res := GenHeader{
 		sharedValidations: sharedValidationsFromSimple(hdr.CommonValidations, true), // NOTE: Required is not defined by the Swagger schema for header. Set arbitrarily to true for convenience in templates.
 		resolvedType:      tpe,
-		Package:           b.GenOpts.LanguageOpts.ManglePackageName(b.APIPackage, "api"),
+		Package:           b.GenOpts.LanguageOpts.ManglePackageName(b.APIPackage, defaultOperationsTarget),
 		ReceiverName:      receiver,
 		ID:                id,
 		Name:              name,
@@ -1036,7 +1005,7 @@ func (b *codeGenOpBuilder) saveResolveContext(resolver *typeResolver, schema *sp
 	if b.PristineDoc == nil {
 		b.PristineDoc = b.Doc.Pristine()
 	}
-	rslv := newTypeResolver(b.GenOpts.LanguageOpts.ManglePackageName(resolver.ModelsPackage, "models"), b.PristineDoc)
+	rslv := newTypeResolver(b.GenOpts.LanguageOpts.ManglePackageName(resolver.ModelsPackage, defaultModelsTarget), b.PristineDoc)
 
 	return rslv, b.cloneSchema(schema)
 }
@@ -1054,7 +1023,7 @@ func (b *codeGenOpBuilder) liftExtraSchemas(resolver, br *typeResolver, bs *spec
 	sc.Schema = *bs
 
 	pg := sc.shallowClone()
-	pkg := b.GenOpts.LanguageOpts.ManglePackageName(resolver.ModelsPackage, "models")
+	pkg := b.GenOpts.LanguageOpts.ManglePackageName(resolver.ModelsPackage, defaultModelsTarget)
 	pg.TypeResolver = newTypeResolver("", rslv.Doc).withKeepDefinitionsPackage(pkg)
 	pg.ExtraSchemas = make(map[string]GenSchema, len(sc.ExtraSchemas))
 
@@ -1169,3 +1138,16 @@ func (b *codeGenOpBuilder) buildOperationSchema(schemaPath, containerName, schem
 	}
 	return schema, nil
 }
+
+func intersectTags(left, right []string) (filtered []string) {
+	if len(right) == 0 {
+		filtered = left
+		return
+	}
+	for _, l := range left {
+		if swag.ContainsStrings(right, l) {
+			filtered = append(filtered, l)
+		}
+	}
+	return
+}
diff --git a/generator/shared.go b/generator/shared.go
index a9aa3597..05ad723a 100644
--- a/generator/shared.go
+++ b/generator/shared.go
@@ -16,368 +16,43 @@ package generator
 
 import (
 	"bytes"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"io/ioutil"
 	"log"
 	"os"
-	"path"
 	"path/filepath"
 	"reflect"
-	"regexp"
 	"sort"
 	"strings"
 	"text/template"
-	"unicode"
-
-	swaggererrors "github.com/go-openapi/errors"
 
 	"github.com/go-openapi/analysis"
 	"github.com/go-openapi/loads"
+	"github.com/go-openapi/runtime"
 	"github.com/go-openapi/spec"
-	"github.com/go-openapi/strfmt"
 	"github.com/go-openapi/swag"
-	"github.com/go-openapi/validate"
-	"golang.org/x/tools/imports"
 )
 
 //go:generate go-bindata -mode 420 -modtime 1482416923 -pkg=generator -ignore=.*\.sw? -ignore=.*\.md ./templates/...
+const (
+	// default generation targets structure
+	defaultModelsTarget     = "models"
+	defaultServerTarget     = "restapi"
+	defaultClientTarget     = "client"
+	defaultOperationsTarget = "operations"
+	defaultClientName       = "rest"
+	defaultServerName       = "swagger"
+	defaultScheme           = "http"
+)
 
-// LanguageOpts to describe a language to the code generator
-type LanguageOpts struct {
-	ReservedWords    []string
-	BaseImportFunc   func(string) string `json:"-"`
-	reservedWordsSet map[string]struct{}
-	initialized      bool
-	formatFunc       func(string, []byte) ([]byte, error)
-	fileNameFunc     func(string) string
-}
-
-// Init the language option
-func (l *LanguageOpts) Init() {
-	if !l.initialized {
-		l.initialized = true
-		l.reservedWordsSet = make(map[string]struct{})
-		for _, rw := range l.ReservedWords {
-			l.reservedWordsSet[rw] = struct{}{}
-		}
-	}
-}
-
-// MangleName makes sure a reserved word gets a safe name
-func (l *LanguageOpts) MangleName(name, suffix string) string {
-	if _, ok := l.reservedWordsSet[swag.ToFileName(name)]; !ok {
-		return name
-	}
-	return strings.Join([]string{name, suffix}, "_")
-}
-
-// MangleVarName makes sure a reserved word gets a safe name
-func (l *LanguageOpts) MangleVarName(name string) string {
-	nm := swag.ToVarName(name)
-	if _, ok := l.reservedWordsSet[nm]; !ok {
-		return nm
-	}
-	return nm + "Var"
-}
-
-// MangleFileName makes sure a file name gets a safe name
-func (l *LanguageOpts) MangleFileName(name string) string {
-	if l.fileNameFunc != nil {
-		return l.fileNameFunc(name)
-	}
-	return swag.ToFileName(name)
-}
-
-// ManglePackageName makes sure a package gets a safe name.
-// In case of a file system path (e.g. name contains "/" or "\" on Windows), this return only the last element.
-func (l *LanguageOpts) ManglePackageName(name, suffix string) string {
-	if name == "" {
-		return suffix
-	}
-	pth := filepath.ToSlash(filepath.Clean(name)) // preserve path
-	_, pkg := path.Split(pth)                     // drop path
-	return l.MangleName(swag.ToFileName(pkg), suffix)
-}
-
-// ManglePackagePath makes sure a full package path gets a safe name.
-// Only the last part of the path is altered.
-func (l *LanguageOpts) ManglePackagePath(name string, suffix string) string {
-	if name == "" {
-		return suffix
-	}
-	target := filepath.ToSlash(filepath.Clean(name)) // preserve path
-	parts := strings.Split(target, "/")
-	parts[len(parts)-1] = l.ManglePackageName(parts[len(parts)-1], suffix)
-	return strings.Join(parts, "/")
-}
-
-// FormatContent formats a file with a language specific formatter
-func (l *LanguageOpts) FormatContent(name string, content []byte) ([]byte, error) {
-	if l.formatFunc != nil {
-		return l.formatFunc(name, content)
-	}
-	return content, nil
-}
-
-func (l *LanguageOpts) baseImport(tgt string) string {
-	if l.BaseImportFunc != nil {
-		return l.BaseImportFunc(tgt)
-	}
-	return ""
-}
-
-var golang = GoLangOpts()
-
-// GoLangOpts for rendering items as golang code
-func GoLangOpts() *LanguageOpts {
-	var goOtherReservedSuffixes = map[string]bool{
-		// see:
-		// https://golang.org/src/go/build/syslist.go
-		// https://golang.org/doc/install/source#environment
-
-		// goos
-		"android":   true,
-		"darwin":    true,
-		"dragonfly": true,
-		"freebsd":   true,
-		"js":        true,
-		"linux":     true,
-		"nacl":      true,
-		"netbsd":    true,
-		"openbsd":   true,
-		"plan9":     true,
-		"solaris":   true,
-		"windows":   true,
-		"zos":       true,
-
-		// arch
-		"386":         true,
-		"amd64":       true,
-		"amd64p32":    true,
-		"arm":         true,
-		"armbe":       true,
-		"arm64":       true,
-		"arm64be":     true,
-		"mips":        true,
-		"mipsle":      true,
-		"mips64":      true,
-		"mips64le":    true,
-		"mips64p32":   true,
-		"mips64p32le": true,
-		"ppc":         true,
-		"ppc64":       true,
-		"ppc64le":     true,
-		"riscv":       true,
-		"riscv64":     true,
-		"s390":        true,
-		"s390x":       true,
-		"sparc":       true,
-		"sparc64":     true,
-		"wasm":        true,
-
-		// other reserved suffixes
-		"test": true,
-	}
-
-	opts := new(LanguageOpts)
-	opts.ReservedWords = []string{
-		"break", "default", "func", "interface", "select",
-		"case", "defer", "go", "map", "struct",
-		"chan", "else", "goto", "package", "switch",
-		"const", "fallthrough", "if", "range", "type",
-		"continue", "for", "import", "return", "var",
-	}
-	opts.formatFunc = func(ffn string, content []byte) ([]byte, error) {
-		opts := new(imports.Options)
-		opts.TabIndent = true
-		opts.TabWidth = 2
-		opts.Fragment = true
-		opts.Comments = true
-		return imports.Process(ffn, content, opts)
-	}
-	opts.fileNameFunc = func(name string) string {
-		// whenever a generated file name ends with a suffix
-		// that is meaningful to go build, adds a "swagger"
-		// suffix
-		parts := strings.Split(swag.ToFileName(name), "_")
-		if goOtherReservedSuffixes[parts[len(parts)-1]] {
-			// file name ending with a reserved arch or os name
-			// are appended an innocuous suffix "swagger"
-			parts = append(parts, "swagger")
-		}
-		return strings.Join(parts, "_")
-	}
-
-	opts.BaseImportFunc = func(tgt string) string {
-		tgt = filepath.Clean(tgt)
-		// On Windows, filepath.Abs("") behaves differently than on Unix.
-		// Windows: yields an error, since Abs() does not know the volume.
-		// UNIX: returns current working directory
-		if tgt == "" {
-			tgt = "."
-		}
-		tgtAbsPath, err := filepath.Abs(tgt)
-		if err != nil {
-			log.Fatalf("could not evaluate base import path with target \"%s\": %v", tgt, err)
-		}
-
-		var tgtAbsPathExtended string
-		tgtAbsPathExtended, err = filepath.EvalSymlinks(tgtAbsPath)
-		if err != nil {
-			log.Fatalf("could not evaluate base import path with target \"%s\" (with symlink resolution): %v", tgtAbsPath, err)
-		}
-
-		gopath := os.Getenv("GOPATH")
-		if gopath == "" {
-			gopath = filepath.Join(os.Getenv("HOME"), "go")
-		}
-
-		var pth string
-		for _, gp := range filepath.SplitList(gopath) {
-			// EvalSymLinks also calls the Clean
-			gopathExtended, er := filepath.EvalSymlinks(gp)
-			if er != nil {
-				log.Fatalln(er)
-			}
-			gopathExtended = filepath.Join(gopathExtended, "src")
-			gp = filepath.Join(gp, "src")
-
-			// At this stage we have expanded and unexpanded target path. GOPATH is fully expanded.
-			// Expanded means symlink free.
-			// We compare both types of targetpath
 with gopath.
-			// If any one of them coincides with gopath , it is imperative that
-			// target path lies inside gopath. How?
-			// 		- Case 1: Irrespective of symlinks paths coincide. Both non-expanded paths.
-			// 		- Case 2: Symlink in target path points to location inside GOPATH. (Expanded Target Path)
-			//    - Case 3: Symlink in target path points to directory outside GOPATH (Unexpanded target path)
-
-			// Case 1: - Do nothing case. If non-expanded paths match just generate base import path as if
-			//				   there are no symlinks.
-
-			// Case 2: - Symlink in target path points to location inside GOPATH. (Expanded Target Path)
-			//					 First if will fail. Second if will succeed.
-
-			// Case 3: - Symlink in target path points to directory outside GOPATH (Unexpanded target path)
-			// 					 First if will succeed and break.
-
-			// compares non expanded path for both
-			if ok, relativepath := checkPrefixAndFetchRelativePath(tgtAbsPath, gp); ok {
-				pth = relativepath
-				break
-			}
-
-			// Compares non-expanded target path
-			if ok, relativepath := checkPrefixAndFetchRelativePath(tgtAbsPath, gopathExtended); ok {
-				pth = relativepath
-				break
-			}
-
-			// Compares expanded target path.
-			if ok, relativepath := checkPrefixAndFetchRelativePath(tgtAbsPathExtended, gopathExtended); ok {
-				pth = relativepath
-				break
-			}
-
-		}
-
-		mod, goModuleAbsPath, err := tryResolveModule(tgtAbsPath)
-		switch {
-		case err != nil:
-			log.Fatalf("Failed to resolve module using go.mod file: %s", err)
-		case mod != "":
-			relTgt := relPathToRelGoPath(goModuleAbsPath, tgtAbsPath)
-			if !strings.HasSuffix(mod, relTgt) {
-				return mod + relTgt
-			}
-			return mod
-		}
-
-		if pth == "" {
-			log.Fatalln("target must reside inside a location in the $GOPATH/src or be a module")
-		}
-		return pth
-	}
-	opts.Init()
-	return opts
-}
-
-var moduleRe = regexp.MustCompile(`module[ \t]+([^\s]+)`)
-
-// resolveGoModFile walks up the directory tree starting from 'dir' until it
-// finds a go.mod file. If go.mod is found it will return the related file
-// object. If no go.mod file is found it will return an error.
-func resolveGoModFile(dir string) (*os.File, string, error) {
-	goModPath := filepath.Join(dir, "go.mod")
-	f, err := os.Open(goModPath)
-	if err != nil {
-		if os.IsNotExist(err) && dir != filepath.Dir(dir) {
-			return resolveGoModFile(filepath.Dir(dir))
-		}
-		return nil, "", err
-	}
-	return f, dir, nil
-}
-
-// relPathToRelGoPath takes a relative os path and returns the relative go
-// package path. For unix nothing will change but for windows \ will be
-// converted to /.
-func relPathToRelGoPath(modAbsPath, absPath string) string {
-	if absPath == "." {
-		return ""
-	}
-
-	path := strings.TrimPrefix(absPath, modAbsPath)
-	pathItems := strings.Split(path, string(filepath.Separator))
-	return strings.Join(pathItems, "/")
-}
-
-func tryResolveModule(baseTargetPath string) (string, string, error) {
-	f, goModAbsPath, err := resolveGoModFile(baseTargetPath)
-	switch {
-	case os.IsNotExist(err):
-		return "", "", nil
-	case err != nil:
-		return "", "", err
-	}
-
-	src, err := ioutil.ReadAll(f)
-	if err != nil {
-		return "", "", err
-	}
-
-	match := moduleRe.FindSubmatch(src)
-	if len(match) != 2 {
-		return "", "", nil
-	}
-
-	return string(match[1]), goModAbsPath, nil
-}
-
-func findSwaggerSpec(nm string) (string, error) {
-	specs := []string{"swagger.json", "swagger.yml", "swagger.yaml"}
-	if nm != "" {
-		specs = []string{nm}
-	}
-	var name string
-	for _, nn := range specs {
-		f, err := os.Stat(nn)
-		if err != nil && !os.IsNotExist(err) {
-			return "", err
-		}
-		if err != nil && os.IsNotExist(err) {
-			continue
-		}
-		if f.IsDir() {
-			return "", fmt.Errorf("%s is a directory", nn)
-		}
-		name = nn
-		break
-	}
-	if name == "" {
-		return "", errors.New("couldn't find a swagger spec")
-	}
-	return name, nil
+func init() {
+	// all initializations for the generator package
+	debugOptions()
+	initLanguage()
+	initTemplateRepo()
+	initTypes()
 }
 
 // DefaultSectionOpts for a given opts, this is used when no config file is passed
@@ -521,7 +196,7 @@ func DefaultSectionOpts(gen *GenOpts) {
 
 }
 
-// TemplateOpts allows
+// TemplateOpts allows for codegen customization
 type TemplateOpts struct {
 	Name       string `mapstructure:"name"`
 	Source     string `mapstructure:"source"`
@@ -587,10 +262,11 @@ type GenOpts struct {
 }
 
 // CheckOpts carries out some global consistency checks on options.
-//
-// At the moment, these checks simply protect TargetPath() and SpecPath()
-// functions. More checks may be added here.
 func (g *GenOpts) CheckOpts() error {
+	if g == nil {
+		return errors.New("gen opts are required")
+	}
+
 	if !filepath.IsAbs(g.Target) {
 		if _, err := filepath.Abs(g.Target); err != nil {
 			return fmt.Errorf("could not locate target %s: %v", g.Target, err)
@@ -599,11 +275,22 @@ func (g *GenOpts) CheckOpts() error {
 	if filepath.IsAbs(g.ServerPackage) {
 		return fmt.Errorf("you shouldn't specify an absolute path in --server-package: %s", g.ServerPackage)
 	}
-	if !filepath.IsAbs(g.Spec) && !strings.HasPrefix(g.Spec, "http://") && !strings.HasPrefix(g.Spec, "https://") {
-		if _, err := filepath.Abs(g.Spec); err != nil {
-			return fmt.Errorf("could not locate spec: %s", g.Spec)
-		}
+
+	if strings.HasPrefix(g.Spec, "http://") || strings.HasPrefix(g.Spec, "https://") {
+		return nil
+	}
+
+	pth, err := findSwaggerSpec(g.Spec)
+	if err != nil {
+		return err
 	}
+
+	// ensure spec path is absolute
+	g.Spec, err = filepath.Abs(pth)
+	if err != nil {
+		return fmt.Errorf("could not locate spec: %s", g.Spec)
+	}
+
 	return nil
 }
 
@@ -670,10 +357,13 @@ func (g *GenOpts) EnsureDefaults() error {
 	if g.defaultsEnsured {
 		return nil
 	}
-	DefaultSectionOpts(g)
+
 	if g.LanguageOpts == nil {
-		g.LanguageOpts = GoLangOpts()
+		g.LanguageOpts = DefaultLanguageFunc()
 	}
+
+	DefaultSectionOpts(g)
+
 	// set defaults for flattening options
 	if g.FlattenOpts == nil {
 		g.FlattenOpts = &analysis.FlattenOpts{
@@ -683,6 +373,22 @@ func (g *GenOpts) EnsureDefaults() error {
 			Expand:       false,
 		}
 	}
+
+	if g.DefaultScheme == "" {
+		g.DefaultScheme = defaultScheme
+	}
+
+	if g.DefaultConsumes == "" {
+		g.DefaultConsumes = runtime.JSONMime
+	}
+
+	if g.DefaultProduces == "" {
+		g.DefaultProduces = runtime.JSONMime
+	}
+
+	// always include validator with models
+	g.IncludeValidator = g.IncludeModel
+
 	g.defaultsEnsured = true
 	return nil
 }
@@ -709,12 +415,14 @@ func (g *GenOpts) location(t *TemplateOpts, data interface{}) (string, string, e
 		tags = tagsF.Interface().([]string)
 	}
 
-	pthTpl, err := template.New(t.Name + "-target").Funcs(FuncMap).Parse(t.Target)
+	funcMap := FuncMapFunc(g.LanguageOpts)
+
+	pthTpl, err := template.New(t.Name + "-target").Funcs(funcMap).Parse(t.Target)
 	if err != nil {
 		return "", "", err
 	}
 
-	fNameTpl, err := template.New(t.Name + "-filename").Funcs(FuncMap).Parse(t.FileName)
+	fNameTpl, err := template.New(t.Name + "-filename").Funcs(funcMap).Parse(t.FileName)
 	if err != nil {
 		return "", "", err
 	}
@@ -735,7 +443,6 @@ func (g *GenOpts) location(t *TemplateOpts, data interface{}) (string, string, e
 		Context:       data,
 	}
 
-	// pretty.Println(data)
 	var pthBuf bytes.Buffer
 	if e := pthTpl.Execute(&pthBuf, d); e != nil {
 		return "", "", e
@@ -781,7 +488,7 @@ func (g *GenOpts) render(t *TemplateOpts, data interface{}) ([]byte, error) {
 		if err != nil {
 			return nil, fmt.Errorf("error while opening %s template file: %v", templateFile, err)
 		}
-		tt, err := template.New(t.Source).Funcs(FuncMap).Parse(string(content))
+		tt, err := template.New(t.Source).Funcs(FuncMapFunc(g.LanguageOpts)).Parse(string(content))
 		if err != nil {
 			return nil, fmt.Errorf("template parsing failed on template %s: %v", t.Name, err)
 		}
@@ -934,42 +641,25 @@ func (g *GenOpts) renderDefinition(gg *GenDefinition) error {
 	return nil
 }
 
-func validateSpec(path string, doc *loads.Document) (err error) {
-	if doc == nil {
-		if path, doc, err = loadSpec(path); err != nil {
+func (g *GenOpts) setTemplates() error {
+	templates.LoadDefaults()
+
+	if g.Template != "" {
+		// set contrib templates
+		if err := templates.LoadContrib(g.Template); err != nil {
 			return err
 		}
 	}
 
-	result := validate.Spec(doc, strfmt.Default)
-	if result == nil {
-		return nil
-	}
-
-	str := fmt.Sprintf("The swagger spec at %q is invalid against swagger specification %s. see errors :\n", path, doc.Version())
-	for _, desc := range result.(*swaggererrors.CompositeError).Errors {
-		str += fmt.Sprintf("- %s\n", desc)
-	}
-	return errors.New(str)
-}
+	templates.SetAllowOverride(g.AllowTemplateOverride)
 
-func loadSpec(specFile string) (string, *loads.Document, error) {
-	// find swagger spec document, verify it exists
-	specPath := specFile
-	var err error
-	if !strings.HasPrefix(specPath, "http") {
-		specPath, err = findSwaggerSpec(specFile)
-		if err != nil {
-			return "", nil, err
+	if g.TemplateDir != "" {
+		// set custom templates
+		if err := templates.LoadDir(g.TemplateDir); err != nil {
+			return err
 		}
 	}
-
-	// load swagger spec
-	specDoc, err := loads.Spec(specPath)
-	if err != nil {
-		return "", nil, err
-	}
-	return specPath, specDoc, nil
+	return nil
 }
 
 func fileExists(target, name string) bool {
@@ -1017,15 +707,6 @@ func appNameOrDefault(specDoc *loads.Document, name, defaultName string) string
 	return strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(swag.ToGoName(name), "Test"), "API"), "Test")
 }
 
-func containsString(names []string, name string) bool {
-	for _, nm := range names {
-		if nm == name {
-			return true
-		}
-	}
-	return false
-}
-
 type opRef struct {
 	Method string
 	Path   string
@@ -1070,7 +751,7 @@ func gatherOperations(specDoc *analysis.Spec, operationIDs []string) map[string]
 		if found && oo.Method != opr.Method && oo.Path != opr.Path {
 			nm = opr.Key
 		}
-		if len(operationIDs) == 0 || containsString(operationIDs, opr.ID) || containsString(operationIDs, nm) {
+		if len(operationIDs) == 0 || swag.ContainsStrings(operationIDs, opr.ID) || swag.ContainsStrings(operationIDs, nm) {
 			opr.ID = nm
 			opr.Op.ID = nm
 			operations[nm] = opr
@@ -1080,43 +761,6 @@ func gatherOperations(specDoc *analysis.Spec, operationIDs []string) map[string]
 	return operations
 }
 
-func pascalize(arg string) string {
-	runes := []rune(arg)
-	switch len(runes) {
-	case 0:
-		return "Empty"
-	case 1: // handle special case when we have a single rune that is not handled by swag.ToGoName
-		switch runes[0] {
-		case '+', '-', '#', '_': // those cases are handled differently than swag utility
-			return prefixForName(arg)
-		}
-	}
-	return swag.ToGoName(swag.ToGoName(arg)) // want to remove spaces
-}
-
-func prefixForName(arg string) string {
-	first := []rune(arg)[0]
-	if len(arg) == 0 || unicode.IsLetter(first) {
-		return ""
-	}
-	switch first {
-	case '+':
-		return "Plus"
-	case '-':
-		return "Minus"
-	case '#':
-		return "HashTag"
-		// other cases ($,@ etc..) handled by swag.ToGoName
-	}
-	return "Nr"
-}
-
-func init() {
-	// this makes the ToGoName func behave with the special
-	// prefixing rule above
-	swag.GoNamePrefixFunc = prefixForName
-}
-
 func pruneEmpty(in []string) (out []string) {
 	for _, v := range in {
 		if v != "" {
@@ -1130,73 +774,6 @@ func trimBOM(in string) string {
 	return strings.Trim(in, "\xef\xbb\xbf")
 }
 
-func validateAndFlattenSpec(opts *GenOpts, specDoc *loads.Document) (*loads.Document, error) {
-
-	var err error
-
-	// Validate if needed
-	if opts.ValidateSpec {
-		log.Printf("validating spec %v", opts.Spec)
-		if erv := validateSpec(opts.Spec, specDoc); erv != nil {
-			return specDoc, erv
-		}
-	}
-
-	// Restore spec to original
-	opts.Spec, specDoc, err = loadSpec(opts.Spec)
-	if err != nil {
-		return nil, err
-	}
-
-	absBasePath := specDoc.SpecFilePath()
-	if !filepath.IsAbs(absBasePath) {
-		cwd, _ := os.Getwd()
-		absBasePath = filepath.Join(cwd, absBasePath)
-	}
-
-	// Some preprocessing is required before codegen
-	//
-	// This ensures at least that $ref's in the spec document are canonical,
-	// i.e all $ref are local to this file and point to some uniquely named definition.
-	//
-	// Default option is to ensure minimal flattening of $ref, bundling remote $refs and relocating arbitrary JSON
-	// pointers as definitions.
-	// This preprocessing may introduce duplicate names (e.g. remote $ref with same name). In this case, a definition
-	// suffixed with "OAIGen" is produced.
-	//
-	// Full flattening option farther transforms the spec by moving every complex object (e.g. with some properties)
-	// as a standalone definition.
-	//
-	// Eventually, an "expand spec" option is available. It is essentially useful for testing purposes.
-	//
-	// NOTE(fredbi): spec expansion may produce some unsupported constructs and is not yet protected against the
-	// following cases:
-	//  - polymorphic types generation may fail with expansion (expand destructs the reuse intent of the $ref in allOf)
-	//  - name duplicates may occur and result in compilation failures
-	// The right place to fix these shortcomings is go-openapi/analysis.
-
-	opts.FlattenOpts.BasePath = absBasePath // BasePath must be absolute
-	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
-
-	var preprocessingOption string
-	switch {
-	case opts.FlattenOpts.Expand:
-		preprocessingOption = "expand"
-	case opts.FlattenOpts.Minimal:
-		preprocessingOption = "minimal flattening"
-	default:
-		preprocessingOption = "full flattening"
-	}
-	log.Printf("preprocessing spec with option:  %s", preprocessingOption)
-
-	if err = analysis.Flatten(*opts.FlattenOpts); err != nil {
-		return nil, err
-	}
-
-	// yields the preprocessed spec document
-	return specDoc, nil
-}
-
 // gatherSecuritySchemes produces a sorted representation from a map of spec security schemes
 func gatherSecuritySchemes(securitySchemes map[string]spec.SecurityScheme, appName, principal, receiver string) (security GenSecuritySchemes) {
 	for scheme, req := range securitySchemes {
@@ -1289,3 +866,12 @@ func sharedValidationsFromSchema(v spec.Schema, isRequired bool) (sh sharedValid
 	}
 	return
 }
+
+func dumpData(data interface{}) error {
+	bb, err := json.MarshalIndent(data, "", "  ")
+	if err != nil {
+		return err
+	}
+	fmt.Fprintln(os.Stdout, string(bb))
+	return nil
+}
diff --git a/generator/spec.go b/generator/spec.go
new file mode 100644
index 00000000..ebd28393
--- /dev/null
+++ b/generator/spec.go
@@ -0,0 +1,215 @@
+package generator
+
+import (
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+
+	"github.com/go-openapi/analysis"
+	swaggererrors "github.com/go-openapi/errors"
+	"github.com/go-openapi/loads"
+	"github.com/go-openapi/strfmt"
+	"github.com/go-openapi/swag"
+	"github.com/go-openapi/validate"
+	"gopkg.in/yaml.v2"
+)
+
+func (g *GenOpts) validateAndFlattenSpec() (*loads.Document, error) {
+	// Load spec document
+	specDoc, err := loads.Spec(g.Spec)
+	if err != nil {
+		return nil, err
+	}
+
+	// Validate if needed
+	if g.ValidateSpec {
+		log.Printf("validating spec %v", g.Spec)
+		validationErrors := validate.Spec(specDoc, strfmt.Default)
+		if validationErrors != nil {
+			str := fmt.Sprintf("The swagger spec at %q is invalid against swagger specification %s. see errors :\n",
+				g.Spec, specDoc.Version())
+			for _, desc := range validationErrors.(*swaggererrors.CompositeError).Errors {
+				str += fmt.Sprintf("- %s\n", desc)
+			}
+			return nil, errors.New(str)
+		}
+		// TODO(fredbi): due to uncontrolled $ref state in spec, we need to reload the spec atm, or flatten won't
+		// work properly (validate expansion alters the $ref cache in go-openapi/spec)
+		specDoc, _ = loads.Spec(g.Spec)
+	}
+
+	// Flatten spec
+	//
+	// Some preprocessing is required before codegen
+	//
+	// This ensures at least that $ref's in the spec document are canonical,
+	// i.e all $ref are local to this file and point to some uniquely named definition.
+	//
+	// Default option is to ensure minimal flattening of $ref, bundling remote $refs and relocating arbitrary JSON
+	// pointers as definitions.
+	// This preprocessing may introduce duplicate names (e.g. remote $ref with same name). In this case, a definition
+	// suffixed with "OAIGen" is produced.
+	//
+	// Full flattening option farther transforms the spec by moving every complex object (e.g. with some properties)
+	// as a standalone definition.
+	//
+	// Eventually, an "expand spec" option is available. It is essentially useful for testing purposes.
+	//
+	// NOTE(fredbi): spec expansion may produce some unsupported constructs and is not yet protected against the
+	// following cases:
+	//  - polymorphic types generation may fail with expansion (expand destructs the reuse intent of the $ref in allOf)
+	//  - name duplicates may occur and result in compilation failures
+	//
+	// The right place to fix these shortcomings is go-openapi/analysis.
+
+	g.FlattenOpts.BasePath = specDoc.SpecFilePath()
+	g.FlattenOpts.Spec = analysis.New(specDoc.Spec())
+
+	g.printFlattenOpts()
+
+	if err = analysis.Flatten(*g.FlattenOpts); err != nil {
+		return nil, err
+	}
+
+	// yields the preprocessed spec document
+	return specDoc, nil
+}
+
+func (g *GenOpts) analyzeSpec() (*loads.Document, *analysis.Spec, error) {
+	// spec preprocessing option
+	if g.PropertiesSpecOrder {
+		g.Spec = WithAutoXOrder(g.Spec)
+	}
+
+	// load, validate and flatten
+	specDoc, err := g.validateAndFlattenSpec()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// analyze the spec
+	analyzed := analysis.New(specDoc.Spec())
+
+	return specDoc, analyzed, nil
+}
+
+func (g *GenOpts) printFlattenOpts() {
+	var preprocessingOption string
+	switch {
+	case g.FlattenOpts.Expand:
+		preprocessingOption = "expand"
+	case g.FlattenOpts.Minimal:
+		preprocessingOption = "minimal flattening"
+	default:
+		preprocessingOption = "full flattening"
+	}
+	log.Printf("preprocessing spec with option:  %s", preprocessingOption)
+}
+
+//findSwaggerSpec fetches a default swagger spec if none is provided
+func findSwaggerSpec(nm string) (string, error) {
+	specs := []string{"swagger.json", "swagger.yml", "swagger.yaml"}
+	if nm != "" {
+		specs = []string{nm}
+	}
+	var name string
+	for _, nn := range specs {
+		f, err := os.Stat(nn)
+		if err != nil {
+			if os.IsNotExist(err) {
+				continue
+			}
+			return "", err
+		}
+		if f.IsDir() {
+			return "", fmt.Errorf("%s is a directory", nn)
+		}
+		name = nn
+		break
+	}
+	if name == "" {
+		return "", errors.New("couldn't find a swagger spec")
+	}
+	return name, nil
+}
+
+// WithAutoXOrder amends the spec to specify property order as they appear
+// in the spec (supports yaml documents only).
+func WithAutoXOrder(specPath string) string {
+	lookFor := func(ele interface{}, key string) (yaml.MapSlice, bool) {
+		if slice, ok := ele.(yaml.MapSlice); ok {
+			for _, v := range slice {
+				if v.Key == key {
+					if slice, ok := v.Value.(yaml.MapSlice); ok {
+						return slice, ok
+					}
+				}
+			}
+		}
+		return nil, false
+	}
+
+	var addXOrder func(interface{})
+	addXOrder = func(element interface{}) {
+		if props, ok := lookFor(element, "properties"); ok {
+			for i, prop := range props {
+				if pSlice, ok := prop.Value.(yaml.MapSlice); ok {
+					isObject := false
+					xOrderIndex := -1 //Find if x-order already exists
+
+					for i, v := range pSlice {
+						if v.Key == "type" && v.Value == object {
+							isObject = true
+						}
+						if v.Key == xOrder {
+							xOrderIndex = i
+							break
+						}
+					}
+
+					if xOrderIndex > -1 { //Override existing x-order
+						pSlice[xOrderIndex] = yaml.MapItem{Key: xOrder, Value: i}
+					} else { // append new x-order
+						pSlice = append(pSlice, yaml.MapItem{Key: xOrder, Value: i})
+					}
+					prop.Value = pSlice
+					props[i] = prop
+
+					if isObject {
+						addXOrder(pSlice)
+					}
+				}
+			}
+		}
+	}
+
+	yamlDoc, err := swag.YAMLData(specPath)
+	if err != nil {
+		panic(err)
+	}
+
+	if defs, ok := lookFor(yamlDoc, "definitions"); ok {
+		for _, def := range defs {
+			addXOrder(def.Value)
+		}
+	}
+
+	addXOrder(yamlDoc)
+
+	out, err := yaml.Marshal(yamlDoc)
+	if err != nil {
+		panic(err)
+	}
+
+	tmpFile, err := ioutil.TempFile("", filepath.Base(specPath))
+	if err != nil {
+		panic(err)
+	}
+	if err := ioutil.WriteFile(tmpFile.Name(), out, 0); err != nil {
+		panic(err)
+	}
+	return tmpFile.Name()
+}
diff --git a/generator/support.go b/generator/support.go
index 11d5181c..35f2c4cf 100644
--- a/generator/support.go
+++ b/generator/support.go
@@ -1,4 +1,5 @@
 // Copyright 2015 go-swagger maintainers
+
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -19,20 +20,13 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"log"
-	"os"
 	"path"
 	"path/filepath"
-	goruntime "runtime"
 	"sort"
-	"strings"
-
-	yaml "gopkg.in/yaml.v2"
 
 	"github.com/go-openapi/analysis"
 	"github.com/go-openapi/loads"
-	"github.com/go-openapi/runtime"
 	"github.com/go-openapi/spec"
 	"github.com/go-openapi/swag"
 )
@@ -56,85 +50,32 @@ func GenerateSupport(name string, modelNames, operationIDs []string, opts *GenOp
 }
 
 func newAppGenerator(name string, modelNames, operationIDs []string, opts *GenOpts) (*appGenerator, error) {
-	if opts == nil {
-		return nil, errors.New("gen opts are required")
-	}
 	if err := opts.CheckOpts(); err != nil {
 		return nil, err
 	}
 
-	templates.LoadDefaults()
-	if opts.Template != "" {
-		if err := templates.LoadContrib(opts.Template); err != nil {
-			return nil, err
-		}
-	}
-
-	templates.SetAllowOverride(opts.AllowTemplateOverride)
-
-	if opts.TemplateDir != "" {
-		if err := templates.LoadDir(opts.TemplateDir); err != nil {
-			return nil, err
-		}
-	}
-
-	// Load the spec
-	var err error
-	var specDoc *loads.Document
-
-	opts.Spec, err = findSwaggerSpec(opts.Spec)
-	if err != nil {
-		return nil, err
-	}
-
-	if !filepath.IsAbs(opts.Spec) {
-		cwd, _ := os.Getwd()
-		opts.Spec = filepath.Join(cwd, opts.Spec)
-	}
-
-	if opts.PropertiesSpecOrder {
-		opts.Spec = WithAutoXOrder(opts.Spec)
-	}
-
-	opts.Spec, specDoc, err = loadSpec(opts.Spec)
-	if err != nil {
+	if err := opts.setTemplates(); err != nil {
 		return nil, err
 	}
 
-	specDoc, err = validateAndFlattenSpec(opts, specDoc)
+	specDoc, analyzed, err := opts.analyzeSpec()
 	if err != nil {
 		return nil, err
 	}
 
-	analyzed := analysis.New(specDoc.Spec())
-
 	models, err := gatherModels(specDoc, modelNames)
 	if err != nil {
 		return nil, err
 	}
 
 	operations := gatherOperations(analyzed, operationIDs)
+
 	if len(operations) == 0 {
 		return nil, errors.New("no operations were selected")
 	}
 
-	defaultScheme := opts.DefaultScheme
-	if defaultScheme == "" {
-		defaultScheme = "http"
-	}
-
-	defaultProduces := opts.DefaultProduces
-	if defaultProduces == "" {
-		defaultProduces = runtime.JSONMime
-	}
-
-	defaultConsumes := opts.DefaultConsumes
-	if defaultConsumes == "" {
-		defaultConsumes = runtime.JSONMime
-	}
-
-	opts.Name = appNameOrDefault(specDoc, name, "swagger")
-	apiPackage := opts.LanguageOpts.ManglePackagePath(opts.APIPackage, "api")
+	opts.Name = appNameOrDefault(specDoc, name, defaultServerName)
+	apiPackage := opts.LanguageOpts.ManglePackagePath(opts.APIPackage, defaultOperationsTarget)
 	return &appGenerator{
 		Name:              opts.Name,
 		Receiver:          "o",
@@ -144,16 +85,16 @@ func newAppGenerator(name string, modelNames, operationIDs []string, opts *GenOp
 		Operations:        operations,
 		Target:            opts.Target,
 		DumpData:          opts.DumpData,
-		Package:           opts.LanguageOpts.ManglePackageName(apiPackage, "api"),
+		Package:           opts.LanguageOpts.ManglePackageName(apiPackage, defaultOperationsTarget),
 		APIPackage:        apiPackage,
-		ModelsPackage:     opts.LanguageOpts.ManglePackagePath(opts.ModelPackage, "definitions"),
-		ServerPackage:     opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, "server"),
-		ClientPackage:     opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, "client"),
-		OperationsPackage: filepath.Join(opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, "server"), apiPackage),
+		ModelsPackage:     opts.LanguageOpts.ManglePackagePath(opts.ModelPackage, defaultModelsTarget),
+		ServerPackage:     opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, defaultServerTarget),
+		ClientPackage:     opts.LanguageOpts.ManglePackagePath(opts.ClientPackage, defaultClientTarget),
+		OperationsPackage: filepath.Join(opts.LanguageOpts.ManglePackagePath(opts.ServerPackage, defaultServerTarget), apiPackage),
 		Principal:         opts.Principal,
-		DefaultScheme:     defaultScheme,
-		DefaultProduces:   defaultProduces,
-		DefaultConsumes:   defaultConsumes,
+		DefaultScheme:     opts.DefaultScheme,
+		DefaultProduces:   opts.DefaultProduces,
+		DefaultConsumes:   opts.DefaultConsumes,
 		GenOpts:           opts,
 	}, nil
 }
@@ -180,122 +121,14 @@ type appGenerator struct {
 	GenOpts           *GenOpts
 }
 
-// WithAutoXOrder amends the spec to specify property order as they appear
-// in the spec (supports yaml documents only).
-func WithAutoXOrder(specPath string) string {
-	lookFor := func(ele interface{}, key string) (yaml.MapSlice, bool) {
-		if slice, ok := ele.(yaml.MapSlice); ok {
-			for _, v := range slice {
-				if v.Key == key {
-					if slice, ok := v.Value.(yaml.MapSlice); ok {
-						return slice, ok
-					}
-				}
-			}
-		}
-		return nil, false
-	}
-
-	var addXOrder func(interface{})
-	addXOrder = func(element interface{}) {
-		if props, ok := lookFor(element, "properties"); ok {
-			for i, prop := range props {
-				if pSlice, ok := prop.Value.(yaml.MapSlice); ok {
-					isObject := false
-					xOrderIndex := -1 //Find if x-order already exists
-
-					for i, v := range pSlice {
-						if v.Key == "type" && v.Value == object {
-							isObject = true
-						}
-						if v.Key == xOrder {
-							xOrderIndex = i
-							break
-						}
-					}
-
-					if xOrderIndex > -1 { //Override existing x-order
-						pSlice[xOrderIndex] = yaml.MapItem{Key: xOrder, Value: i}
-					} else { // append new x-order
-						pSlice = append(pSlice, yaml.MapItem{Key: xOrder, Value: i})
-					}
-					prop.Value = pSlice
-					props[i] = prop
-
-					if isObject {
-						addXOrder(pSlice)
-					}
-				}
-			}
-		}
-	}
-
-	yamlDoc, err := swag.YAMLData(specPath)
-	if err != nil {
-		panic(err)
-	}
-
-	if defs, ok := lookFor(yamlDoc, "definitions"); ok {
-		for _, def := range defs {
-			addXOrder(def.Value)
-		}
-	}
-
-	addXOrder(yamlDoc)
-
-	out, err := yaml.Marshal(yamlDoc)
-	if err != nil {
-		panic(err)
-	}
-
-	tmpFile, err := ioutil.TempFile("", filepath.Base(specPath))
-	if err != nil {
-		panic(err)
-	}
-	if err := ioutil.WriteFile(tmpFile.Name(), out, 0); err != nil {
-		panic(err)
-	}
-	return tmpFile.Name()
-}
-
-// 1. Checks if the child path and parent path coincide.
-// 2. If they do return child path  relative to parent path.
-// 3. Everything else return false
-func checkPrefixAndFetchRelativePath(childpath string, parentpath string) (bool, string) {
-	// Windows (local) file systems - NTFS, as well as FAT and variants
-	// are case insensitive.
-	cp, pp := childpath, parentpath
-	if goruntime.GOOS == "windows" {
-		cp = strings.ToLower(cp)
-		pp = strings.ToLower(pp)
-	}
-
-	if strings.HasPrefix(cp, pp) {
-		pth, err := filepath.Rel(parentpath, childpath)
-		if err != nil {
-			log.Fatalln(err)
-		}
-		return true, pth
-	}
-
-	return false, ""
-
-}
-
 func (a *appGenerator) Generate() error {
-
 	app, err := a.makeCodegenApp()
 	if err != nil {
 		return err
 	}
 
 	if a.DumpData {
-		bb, err := json.MarshalIndent(app, "", "  ")
-		if err != nil {
-			return err
-		}
-		fmt.Fprintln(os.Stdout, string(bb))
-		return nil
+		return dumpData(app)
 	}
 
 	// NOTE: relative to previous implem with chan.
@@ -325,7 +158,7 @@ func (a *appGenerator) Generate() error {
 					return err
 				}
 			}
-			// Optional OperationGroups templates generation
+			// optional OperationGroups templates generation
 			opGroup := opg
 			opGroup.DefaultImports = app.DefaultImports
 			if err := a.GenOpts.renderOperationGroup(&opGroup); err != nil {
@@ -346,6 +179,7 @@ func (a *appGenerator) Generate() error {
 func (a *appGenerator) GenerateSupport(ap *GenApp) error {
 	app := ap
 	if ap == nil {
+		// allows for calling GenerateSupport standalone
 		ca, err := a.makeCodegenApp()
 		if err != nil {
 			return err
@@ -353,10 +187,10 @@ func (a *appGenerator) GenerateSupport(ap *GenApp) error {
 		app = &ca
 	}
 	baseImport := a.GenOpts.LanguageOpts.baseImport(a.Target)
-	importPath := path.Join(filepath.ToSlash(baseImport), a.GenOpts.LanguageOpts.ManglePackagePath(a.OperationsPackage, ""))
+	importPath := path.Join(baseImport, a.GenOpts.LanguageOpts.ManglePackagePath(a.OperationsPackage, ""))
 	app.DefaultImports = append(
 		app.DefaultImports,
-		path.Join(filepath.ToSlash(baseImport), a.GenOpts.LanguageOpts.ManglePackagePath(a.ServerPackage, "")),
+		path.Join(baseImport, a.GenOpts.LanguageOpts.ManglePackagePath(a.ServerPackage, "")),
 		importPath,
 	)
 
@@ -388,8 +222,6 @@ func (a *appGenerator) makeCodegenApp() (GenApp, error) {
 
 	consumes, _ := a.makeConsumes()
 	produces, _ := a.makeProduces()
-	//sort.Sort(consumes) // TODO(fred): done inside
-	//sort.Sort(produces) // TODO(fred): done inside
 	security := a.makeSecuritySchemes()
 	baseImport := a.GenOpts.LanguageOpts.baseImport(a.Target)
 	var imports = make(map[string]string)
@@ -397,9 +229,9 @@ func (a *appGenerator) makeCodegenApp() (GenApp, error) {
 	var genMods GenDefinitions
 	importPath := a.GenOpts.ExistingModels
 	if a.GenOpts.ExistingModels == "" {
-		imports[a.GenOpts.LanguageOpts.ManglePackageName(a.ModelsPackage, "models")] = path.Join(
-			filepath.ToSlash(baseImport),
-			a.GenOpts.LanguageOpts.ManglePackagePath(a.GenOpts.ModelPackage, "models"))
+		imports[a.GenOpts.LanguageOpts.ManglePackageName(a.ModelsPackage, defaultModelsTarget)] = path.Join(
+			baseImport,
+			a.GenOpts.LanguageOpts.ManglePackagePath(a.GenOpts.ModelPackage, defaultModelsTarget))
 	}
 	if importPath != "" {
 		defaultImports = append(defaultImports, importPath)
@@ -439,30 +271,30 @@ func (a *appGenerator) makeCodegenApp() (GenApp, error) {
 		o.Tags = pruneEmpty(o.Tags)
 		o.ID = on
 
-		var bldr codeGenOpBuilder
-		bldr.ModelsPackage = a.ModelsPackage
-		bldr.Principal = a.Principal
-		bldr.Target = a.Target
-		bldr.DefaultImports = defaultImports
-		bldr.Imports = imports
-		bldr.DefaultScheme = a.DefaultScheme
-		bldr.Doc = a.SpecDoc
-		bldr.Analyzed = a.Analyzed
-		bldr.BasePath = a.SpecDoc.BasePath()
-		bldr.GenOpts = a.GenOpts
-
-		// TODO: change operation name to something safe
-		bldr.Name = on
-		bldr.Operation = *o
-		bldr.Method = opp.Method
-		bldr.Path = opp.Path
+		bldr := codeGenOpBuilder{
+			ModelsPackage:    a.ModelsPackage,
+			Principal:        a.Principal,
+			Target:           a.Target,
+			DefaultImports:   defaultImports,
+			Imports:          imports,
+			DefaultScheme:    a.DefaultScheme,
+			Doc:              a.SpecDoc,
+			Analyzed:         a.Analyzed,
+			BasePath:         a.SpecDoc.BasePath(),
+			GenOpts:          a.GenOpts,
+			Name:             on, // TODO: change operation name to something safe
+			Operation:        *o,
+			Method:           opp.Method,
+			Path:             opp.Path,
+			IncludeValidator: true,
+			APIPackage:       a.APIPackage, // defaults to main operations package
+		}
+
 		bldr.Authed = len(a.Analyzed.SecurityRequirementsFor(o)) > 0
 		bldr.Security = a.Analyzed.SecurityRequirementsFor(o)
 		bldr.SecurityDefinitions = a.Analyzed.SecurityDefinitionsFor(o)
-		bldr.RootAPIPackage = a.GenOpts.LanguageOpts.ManglePackageName(a.ServerPackage, "server")
-		bldr.IncludeValidator = true
+		bldr.RootAPIPackage = a.GenOpts.LanguageOpts.ManglePackageName(a.ServerPackage, defaultServerTarget)
 
-		bldr.APIPackage = a.APIPackage
 		st := o.Tags
 		if a.GenOpts != nil {
 			st = a.GenOpts.Tags
@@ -491,7 +323,7 @@ func (a *appGenerator) makeCodegenApp() (GenApp, error) {
 	for k := range tns {
 		importPath := filepath.ToSlash(
 			path.Join(
-				filepath.ToSlash(baseImport),
+				baseImport,
 				a.GenOpts.LanguageOpts.ManglePackagePath(a.OperationsPackage, ""),
 				swag.ToFileName(k)))
 		defaultImports = append(defaultImports, importPath)
@@ -528,7 +360,7 @@ func (a *appGenerator) makeCodegenApp() (GenApp, error) {
 		opGroup := GenOperationGroup{
 			GenCommon: GenCommon{
 				Copyright:        a.GenOpts.Copyright,
-				TargetImportPath: filepath.ToSlash(baseImport),
+				TargetImportPath: baseImport,
 			},
 			Name:           k,
 			Operations:     vv,
@@ -540,9 +372,9 @@ func (a *appGenerator) makeCodegenApp() (GenApp, error) {
 		opGroups = append(opGroups, opGroup)
 		var importPath string
 		if k == a.APIPackage {
-			importPath = path.Join(filepath.ToSlash(baseImport), a.GenOpts.LanguageOpts.ManglePackagePath(a.OperationsPackage, ""))
+			importPath = path.Join(baseImport, a.GenOpts.LanguageOpts.ManglePackagePath(a.OperationsPackage, ""))
 		} else {
-			importPath = path.Join(filepath.ToSlash(baseImport), a.GenOpts.LanguageOpts.ManglePackagePath(a.OperationsPackage, ""), k)
+			importPath = path.Join(baseImport, a.GenOpts.LanguageOpts.ManglePackagePath(a.OperationsPackage, ""), k)
 		}
 		defaultImports = append(defaultImports, importPath)
 	}
@@ -572,9 +404,9 @@ func (a *appGenerator) makeCodegenApp() (GenApp, error) {
 	return GenApp{
 		GenCommon: GenCommon{
 			Copyright:        a.GenOpts.Copyright,
-			TargetImportPath: filepath.ToSlash(baseImport),
+			TargetImportPath: baseImport,
 		},
-		APIPackage:          a.GenOpts.LanguageOpts.ManglePackageName(a.ServerPackage, "server"),
+		APIPackage:          a.GenOpts.LanguageOpts.ManglePackageName(a.ServerPackage, defaultServerTarget),
 		Package:             a.Package,
 		ReceiverName:        receiver,
 		Name:                a.Name,
diff --git a/generator/template_repo.go b/generator/template_repo.go
index e5f3d557..b975022b 100644
--- a/generator/template_repo.go
+++ b/generator/template_repo.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 	"text/template"
 	"text/template/parse"
+	"unicode"
 
 	"log"
 
@@ -19,180 +20,153 @@ import (
 	"github.com/kr/pretty"
 )
 
-var templates *Repository
+var (
+	assets             map[string][]byte
+	protectedTemplates map[string]bool
 
-// FuncMap is a map with default functions for use n the templates.
-// These are available in every template
-var FuncMap template.FuncMap = map[string]interface{}{
-	"pascalize": pascalize,
-	"camelize":  swag.ToJSONName,
-	"varname":   golang.MangleVarName,
-	"humanize":  swag.ToHumanNameLower,
-	"snakize":   golang.MangleFileName,
-	"toPackagePath": func(name string) string {
-		return filepath.FromSlash(golang.ManglePackagePath(name, ""))
-	},
-	"toPackage": func(name string) string {
-		return golang.ManglePackagePath(name, "")
-	},
-	"toPackageName": func(name string) string {
-		return golang.ManglePackageName(name, "")
-	},
-	"dasherize": swag.ToCommandName,
-	"pluralizeFirstWord": func(arg string) string {
-		sentence := strings.Split(arg, " ")
-		if len(sentence) == 1 {
-			return inflect.Pluralize(arg)
-		}
+	// FuncMapFunc yields a map with all functions for templates
+	FuncMapFunc func(*LanguageOpts) template.FuncMap
 
-		return inflect.Pluralize(sentence[0]) + " " + strings.Join(sentence[1:], " ")
-	},
-	"json":       asJSON,
-	"prettyjson": asPrettyJSON,
-	"hasInsecure": func(arg []string) bool {
-		return swag.ContainsStringsCI(arg, "http") || swag.ContainsStringsCI(arg, "ws")
-	},
-	"hasSecure": func(arg []string) bool {
-		return swag.ContainsStringsCI(arg, "https") || swag.ContainsStringsCI(arg, "wss")
-	},
-	// TODO: simplify redundant functions
-	"stripPackage": func(str, pkg string) string {
-		parts := strings.Split(str, ".")
-		strlen := len(parts)
-		if strlen > 0 {
-			return parts[strlen-1]
-		}
-		return str
-	},
-	"dropPackage": func(str string) string {
-		parts := strings.Split(str, ".")
-		strlen := len(parts)
-		if strlen > 0 {
-			return parts[strlen-1]
-		}
-		return str
-	},
-	"upper": strings.ToUpper,
-	"contains": func(coll []string, arg string) bool {
-		for _, v := range coll {
-			if v == arg {
-				return true
-			}
-		}
-		return false
-	},
-	"padSurround": func(entry, padWith string, i, ln int) string {
-		var res []string
-		if i > 0 {
-			for j := 0; j < i; j++ {
-				res = append(res, padWith)
-			}
-		}
-		res = append(res, entry)
-		tot := ln - i - 1
-		for j := 0; j < tot; j++ {
-			res = append(res, padWith)
-		}
-		return strings.Join(res, ",")
-	},
-	"joinFilePath": filepath.Join,
-	"comment": func(str string, pads ...string) string {
-		// pads specifes padding to indent multi line comments.Defaults to one space
-		pad := " "
-		lines := strings.Split(str, "\n")
-		if len(pads) > 0 {
-			pad = strings.Join(pads, "")
-		}
-		return (strings.Join(lines, "\n//"+pad))
-	},
-	"blockcomment": func(str string) string {
-		return strings.Replace(str, "*/", "[*]/", -1)
-	},
-	"inspect":            pretty.Sprint,
-	"cleanPath":          path.Clean,
-	"mediaTypeName":      mediaMime,
-	"goSliceInitializer": goSliceInitializer,
-	"hasPrefix":          strings.HasPrefix,
-	"stringContains":     strings.Contains,
+	templates *Repository
+)
+
+func initTemplateRepo() {
+	FuncMapFunc = DefaultFuncMap
+
+	// this makes the ToGoName func behave with the special
+	// prefixing rule above
+	swag.GoNamePrefixFunc = prefixForName
+
+	assets = defaultAssets()
+	protectedTemplates = defaultProtectedTemplates()
+	templates = NewRepository(FuncMapFunc(DefaultLanguageFunc()))
 }
 
-func init() {
-	templates = NewRepository(FuncMap)
+// DefaultFuncMap yields a map with default functions for use n the templates.
+// These are available in every template
+func DefaultFuncMap(lang *LanguageOpts) template.FuncMap {
+	return template.FuncMap(map[string]interface{}{
+		"pascalize": pascalize,
+		"camelize":  swag.ToJSONName,
+		"varname":   lang.MangleVarName,
+		"humanize":  swag.ToHumanNameLower,
+		"snakize":   lang.MangleFileName,
+		"toPackagePath": func(name string) string {
+			return filepath.FromSlash(lang.ManglePackagePath(name, ""))
+		},
+		"toPackage": func(name string) string {
+			return lang.ManglePackagePath(name, "")
+		},
+		"toPackageName": func(name string) string {
+			return lang.ManglePackageName(name, "")
+		},
+		"dasherize":          swag.ToCommandName,
+		"pluralizeFirstWord": pluralizeFirstWord,
+		"json":               asJSON,
+		"prettyjson":         asPrettyJSON,
+		"hasInsecure": func(arg []string) bool {
+			return swag.ContainsStringsCI(arg, "http") || swag.ContainsStringsCI(arg, "ws")
+		},
+		"hasSecure": func(arg []string) bool {
+			return swag.ContainsStringsCI(arg, "https") || swag.ContainsStringsCI(arg, "wss")
+		},
+		// TODO: simplify redundant functions
+		"stripPackage": func(str, _ string) string {
+			return dropPackage(str)
+		},
+		"dropPackage":        dropPackage,
+		"upper":              strings.ToUpper,
+		"contains":           swag.ContainsStrings,
+		"padSurround":        padSurround,
+		"joinFilePath":       filepath.Join,
+		"comment":            padComment,
+		"blockcomment":       blockComment,
+		"inspect":            pretty.Sprint,
+		"cleanPath":          path.Clean,
+		"mediaTypeName":      mediaMime,
+		"goSliceInitializer": lang.ArrayInitializerFunc,
+		"hasPrefix":          strings.HasPrefix,
+		"stringContains":     strings.Contains,
+	})
 }
 
-var assets = map[string][]byte{
-	"validation/primitive.gotmpl":           MustAsset("templates/validation/primitive.gotmpl"),
-	"validation/customformat.gotmpl":        MustAsset("templates/validation/customformat.gotmpl"),
-	"docstring.gotmpl":                      MustAsset("templates/docstring.gotmpl"),
-	"validation/structfield.gotmpl":         MustAsset("templates/validation/structfield.gotmpl"),
-	"modelvalidator.gotmpl":                 MustAsset("templates/modelvalidator.gotmpl"),
-	"structfield.gotmpl":                    MustAsset("templates/structfield.gotmpl"),
-	"tupleserializer.gotmpl":                MustAsset("templates/tupleserializer.gotmpl"),
-	"additionalpropertiesserializer.gotmpl": MustAsset("templates/additionalpropertiesserializer.gotmpl"),
-	"schematype.gotmpl":                     MustAsset("templates/schematype.gotmpl"),
-	"schemabody.gotmpl":                     MustAsset("templates/schemabody.gotmpl"),
-	"schema.gotmpl":                         MustAsset("templates/schema.gotmpl"),
-	"schemavalidator.gotmpl":                MustAsset("templates/schemavalidator.gotmpl"),
-	"model.gotmpl":                          MustAsset("templates/model.gotmpl"),
-	"header.gotmpl":                         MustAsset("templates/header.gotmpl"),
-	"swagger_json_embed.gotmpl":             MustAsset("templates/swagger_json_embed.gotmpl"),
-
-	"server/parameter.gotmpl":    MustAsset("templates/server/parameter.gotmpl"),
-	"server/urlbuilder.gotmpl":   MustAsset("templates/server/urlbuilder.gotmpl"),
-	"server/responses.gotmpl":    MustAsset("templates/server/responses.gotmpl"),
-	"server/operation.gotmpl":    MustAsset("templates/server/operation.gotmpl"),
-	"server/builder.gotmpl":      MustAsset("templates/server/builder.gotmpl"),
-	"server/server.gotmpl":       MustAsset("templates/server/server.gotmpl"),
-	"server/configureapi.gotmpl": MustAsset("templates/server/configureapi.gotmpl"),
-	"server/main.gotmpl":         MustAsset("templates/server/main.gotmpl"),
-	"server/doc.gotmpl":          MustAsset("templates/server/doc.gotmpl"),
-
-	"client/parameter.gotmpl": MustAsset("templates/client/parameter.gotmpl"),
-	"client/response.gotmpl":  MustAsset("templates/client/response.gotmpl"),
-	"client/client.gotmpl":    MustAsset("templates/client/client.gotmpl"),
-	"client/facade.gotmpl":    MustAsset("templates/client/facade.gotmpl"),
+func defaultAssets() map[string][]byte {
+	return map[string][]byte{
+		"validation/primitive.gotmpl":           MustAsset("templates/validation/primitive.gotmpl"),
+		"validation/customformat.gotmpl":        MustAsset("templates/validation/customformat.gotmpl"),
+		"docstring.gotmpl":                      MustAsset("templates/docstring.gotmpl"),
+		"validation/structfield.gotmpl":         MustAsset("templates/validation/structfield.gotmpl"),
+		"modelvalidator.gotmpl":                 MustAsset("templates/modelvalidator.gotmpl"),
+		"structfield.gotmpl":                    MustAsset("templates/structfield.gotmpl"),
+		"tupleserializer.gotmpl":                MustAsset("templates/tupleserializer.gotmpl"),
+		"additionalpropertiesserializer.gotmpl": MustAsset("templates/additionalpropertiesserializer.gotmpl"),
+		"schematype.gotmpl":                     MustAsset("templates/schematype.gotmpl"),
+		"schemabody.gotmpl":                     MustAsset("templates/schemabody.gotmpl"),
+		"schema.gotmpl":                         MustAsset("templates/schema.gotmpl"),
+		"schemavalidator.gotmpl":                MustAsset("templates/schemavalidator.gotmpl"),
+		"model.gotmpl":                          MustAsset("templates/model.gotmpl"),
+		"header.gotmpl":                         MustAsset("templates/header.gotmpl"),
+		"swagger_json_embed.gotmpl":             MustAsset("templates/swagger_json_embed.gotmpl"),
+
+		"server/parameter.gotmpl":    MustAsset("templates/server/parameter.gotmpl"),
+		"server/urlbuilder.gotmpl":   MustAsset("templates/server/urlbuilder.gotmpl"),
+		"server/responses.gotmpl":    MustAsset("templates/server/responses.gotmpl"),
+		"server/operation.gotmpl":    MustAsset("templates/server/operation.gotmpl"),
+		"server/builder.gotmpl":      MustAsset("templates/server/builder.gotmpl"),
+		"server/server.gotmpl":       MustAsset("templates/server/server.gotmpl"),
+		"server/configureapi.gotmpl": MustAsset("templates/server/configureapi.gotmpl"),
+		"server/main.gotmpl":         MustAsset("templates/server/main.gotmpl"),
+		"server/doc.gotmpl":          MustAsset("templates/server/doc.gotmpl"),
+
+		"client/parameter.gotmpl": MustAsset("templates/client/parameter.gotmpl"),
+		"client/response.gotmpl":  MustAsset("templates/client/response.gotmpl"),
+		"client/client.gotmpl":    MustAsset("templates/client/client.gotmpl"),
+		"client/facade.gotmpl":    MustAsset("templates/client/facade.gotmpl"),
+	}
 }
 
-var protectedTemplates = map[string]bool{
-	"schemabody":                     true,
-	"privtuplefield":                 true,
-	"withoutBaseTypeBody":            true,
-	"swaggerJsonEmbed":               true,
-	"validationCustomformat":         true,
-	"tuplefield":                     true,
-	"header":                         true,
-	"withBaseTypeBody":               true,
-	"primitivefieldvalidator":        true,
-	"mapvalidator":                   true,
-	"propertyValidationDocString":    true,
-	"typeSchemaType":                 true,
-	"docstring":                      true,
-	"dereffedSchemaType":             true,
-	"model":                          true,
-	"modelvalidator":                 true,
-	"privstructfield":                true,
-	"schemavalidator":                true,
-	"tuplefieldIface":                true,
-	"tupleSerializer":                true,
-	"tupleserializer":                true,
-	"schemaSerializer":               true,
-	"propertyvalidator":              true,
-	"structfieldIface":               true,
-	"schemaBody":                     true,
-	"objectvalidator":                true,
-	"schematype":                     true,
-	"additionalpropertiesserializer": true,
-	"slicevalidator":                 true,
-	"validationStructfield":          true,
-	"validationPrimitive":            true,
-	"schemaType":                     true,
-	"subTypeBody":                    true,
-	"schema":                         true,
-	"additionalPropertiesSerializer": true,
-	"serverDoc":                      true,
-	"structfield":                    true,
-	"hasDiscriminatedSerializer":     true,
-	"discriminatedSerializer":        true,
+func defaultProtectedTemplates() map[string]bool {
+	return map[string]bool{
+		"schemabody":                     true,
+		"privtuplefield":                 true,
+		"withoutBaseTypeBody":            true,
+		"swaggerJsonEmbed":               true,
+		"validationCustomformat":         true,
+		"tuplefield":                     true,
+		"header":                         true,
+		"withBaseTypeBody":               true,
+		"primitivefieldvalidator":        true,
+		"mapvalidator":                   true,
+		"propertyValidationDocString":    true,
+		"typeSchemaType":                 true,
+		"docstring":                      true,
+		"dereffedSchemaType":             true,
+		"model":                          true,
+		"modelvalidator":                 true,
+		"privstructfield":                true,
+		"schemavalidator":                true,
+		"tuplefieldIface":                true,
+		"tupleSerializer":                true,
+		"tupleserializer":                true,
+		"schemaSerializer":               true,
+		"propertyvalidator":              true,
+		"structfieldIface":               true,
+		"schemaBody":                     true,
+		"objectvalidator":                true,
+		"schematype":                     true,
+		"additionalpropertiesserializer": true,
+		"slicevalidator":                 true,
+		"validationStructfield":          true,
+		"validationPrimitive":            true,
+		"schemaType":                     true,
+		"subTypeBody":                    true,
+		"schema":                         true,
+		"additionalPropertiesSerializer": true,
+		"serverDoc":                      true,
+		"structfield":                    true,
+		"hasDiscriminatedSerializer":     true,
+		"discriminatedSerializer":        true,
+	}
 }
 
 // AddFile adds a file to the default repository. It will create a new template based on the filename.
@@ -205,36 +179,6 @@ func AddFile(name, data string) error {
 	return templates.addFile(name, data, false)
 }
 
-func asJSON(data interface{}) (string, error) {
-	b, err := json.Marshal(data)
-	if err != nil {
-		return "", err
-	}
-	return string(b), nil
-}
-
-func asPrettyJSON(data interface{}) (string, error) {
-	b, err := json.MarshalIndent(data, "", "  ")
-	if err != nil {
-		return "", err
-	}
-	return string(b), nil
-}
-
-func goSliceInitializer(data interface{}) (string, error) {
-	// goSliceInitializer constructs a Go literal initializer from interface{} literals.
-	// e.g. []interface{}{"a", "b"} is transformed in {"a","b",}
-	// e.g. map[string]interface{}{ "a": "x", "b": "y"} is transformed in {"a":"x","b":"y",}.
-	//
-	// NOTE: this is currently used to construct simple slice intializers for default values.
-	// This allows for nicer slice initializers for slices of primitive types and avoid systematic use for json.Unmarshal().
-	b, err := json.Marshal(data)
-	if err != nil {
-		return "", err
-	}
-	return strings.Replace(strings.Replace(strings.Replace(string(b), "}", ",}", -1), "[", "{", -1), "]", ",}", -1), nil
-}
-
 // NewRepository creates a new template repository with the provided functions defined
 func NewRepository(funcs template.FuncMap) *Repository {
 	repo := Repository{
@@ -276,8 +220,6 @@ func (t *Repository) LoadDir(templatePath string) error {
 			if assetName, e := filepath.Rel(templatePath, path); e == nil {
 				if data, e := ioutil.ReadFile(path); e == nil {
 					if ee := t.AddFile(assetName, string(data)); ee != nil {
-						// Fatality is decided by caller
-						// log.Fatal(ee)
 						return fmt.Errorf("could not add template: %v", ee)
 					}
 				}
@@ -518,3 +460,95 @@ func (t *Repository) DumpTemplates() {
 	}
 	log.Println(buf.String())
 }
+
+// FuncMap functions
+
+func asJSON(data interface{}) (string, error) {
+	b, err := json.Marshal(data)
+	if err != nil {
+		return "", err
+	}
+	return string(b), nil
+}
+
+func asPrettyJSON(data interface{}) (string, error) {
+	b, err := json.MarshalIndent(data, "", "  ")
+	if err != nil {
+		return "", err
+	}
+	return string(b), nil
+}
+
+func pluralizeFirstWord(arg string) string {
+	sentence := strings.Split(arg, " ")
+	if len(sentence) == 1 {
+		return inflect.Pluralize(arg)
+	}
+
+	return inflect.Pluralize(sentence[0]) + " " + strings.Join(sentence[1:], " ")
+}
+
+func dropPackage(str string) string {
+	parts := strings.Split(str, ".")
+	return parts[len(parts)-1]
+}
+
+func padSurround(entry, padWith string, i, ln int) string {
+	var res []string
+	if i > 0 {
+		for j := 0; j < i; j++ {
+			res = append(res, padWith)
+		}
+	}
+	res = append(res, entry)
+	tot := ln - i - 1
+	for j := 0; j < tot; j++ {
+		res = append(res, padWith)
+	}
+	return strings.Join(res, ",")
+}
+
+func padComment(str string, pads ...string) string {
+	// pads specifes padding to indent multi line comments.Defaults to one space
+	pad := " "
+	lines := strings.Split(str, "\n")
+	if len(pads) > 0 {
+		pad = strings.Join(pads, "")
+	}
+	return (strings.Join(lines, "\n//"+pad))
+}
+
+func blockComment(str string) string {
+	return strings.Replace(str, "*/", "[*]/", -1)
+}
+
+func pascalize(arg string) string {
+	runes := []rune(arg)
+	switch len(runes) {
+	case 0:
+		return "Empty"
+	case 1: // handle special case when we have a single rune that is not handled by swag.ToGoName
+		switch runes[0] {
+		case '+', '-', '#', '_': // those cases are handled differently than swag utility
+			return prefixForName(arg)
+		}
+	}
+	return swag.ToGoName(swag.ToGoName(arg)) // want to remove spaces
+}
+
+func prefixForName(arg string) string {
+	first := []rune(arg)[0]
+	if len(arg) == 0 || unicode.IsLetter(first) {
+		return ""
+	}
+	switch first {
+	case '+':
+		return "Plus"
+	case '-':
+		return "Minus"
+	case '#':
+		return "HashTag"
+		// other cases ($,@ etc..) handled by swag.ToGoName
+	}
+	return "Nr"
+}
diff --git a/generator/types.go b/generator/types.go
index 75deeca4..8a1be5c3 100644
--- a/generator/types.go
+++ b/generator/types.go
@@ -37,7 +37,6 @@ const (
 	str     = "string"
 	object  = "object"
 	binary  = "binary"
-	sHTTP   = "http"
 	body    = "body"
 	b64     = "byte"
 )
@@ -56,10 +55,10 @@ const (
 	xGoJSONString = "x-go-json-string"
 )
 
-// swaggerTypeMapping contains a mapping from go type to swagger type or format
+// swaggerTypeName contains a mapping from go type to swagger type or format
 var swaggerTypeName map[string]string
 
-func init() {
+func initTypes() {
 	swaggerTypeName = make(map[string]string)
 	for k, v := range typeMapping {
 		swaggerTypeName[v] = k


Test patch:
diff --git a/generator/build_test.go b/generator/build_test.go
index 684fa260..e69980d9 100644
--- a/generator/build_test.go
+++ b/generator/build_test.go
@@ -20,7 +20,6 @@ const (
 	defaultAPIPackage    = "operations"
 	defaultClientPackage = "client"
 	defaultModelPackage  = "models"
-	defaultServerPackage = "restapi"
 )
 
 func TestGenerateAndBuild(t *testing.T) {
diff --git a/generator/client_test.go b/generator/client_test.go
index 2303619e..3aa44fb0 100644
--- a/generator/client_test.go
+++ b/generator/client_test.go
@@ -23,25 +23,21 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 const (
-	defaultAPIPackage    = "operations"
-	defaultClientPackage = "client"
-	defaultModelPackage  = "models"
-	defaultServerPackage = "restapi"
-
 	basicFixture = "../fixtures/petstores/petstore.json"
 )
 
-func testClientGenOpts() (g GenOpts) {
+func testClientGenOpts() *GenOpts {
+	g := &GenOpts{}
 	g.Target = "."
 	g.APIPackage = defaultAPIPackage
 	g.ModelPackage = defaultModelPackage
 	g.ServerPackage = defaultServerPackage
 	g.ClientPackage = defaultClientPackage
 	g.Principal = ""
-	g.DefaultScheme = "http"
 	g.IncludeModel = true
 	g.IncludeValidator = true
 	g.IncludeHandler = true
@@ -51,8 +47,10 @@ func testClientGenOpts() (g GenOpts) {
 	g.TemplateDir = ""
 	g.DumpData = false
 	g.IsClient = true
-	_ = g.EnsureDefaults()
-	return
+	if err := g.EnsureDefaults(); err != nil {
+		panic(err)
+	}
+	return g
 }
 
 func Test_GenerateClient(t *testing.T) {
@@ -64,28 +62,34 @@ func Test_GenerateClient(t *testing.T) {
 
 	opts := testClientGenOpts()
 	opts.TemplateDir = "dir/nowhere"
-	err = GenerateClient("test", []string{"model1"}, []string{"op1", "op2"}, &opts)
+	err = GenerateClient("test", []string{"model1"}, []string{"op1", "op2"}, opts)
 	assert.Error(t, err)
 
 	opts = testClientGenOpts()
 	opts.TemplateDir = "http://nowhere.com"
-	err = GenerateClient("test", []string{"model1"}, []string{"op1", "op2"}, &opts)
+	err = GenerateClient("test", []string{"model1"}, []string{"op1", "op2"}, opts)
 	assert.Error(t, err)
 
 	opts = testClientGenOpts()
 	opts.Spec = "dir/nowhere.yaml"
-	err = GenerateClient("test", []string{"model1"}, []string{"op1", "op2"}, &opts)
+	err = GenerateClient("test", []string{"model1"}, []string{"op1", "op2"}, opts)
 	assert.Error(t, err)
 
 	opts = testClientGenOpts()
 	opts.Spec = basicFixture
-	err = GenerateClient("test", []string{"model1"}, []string{}, &opts)
+	err = GenerateClient("test", []string{"model1"}, []string{}, opts)
 	assert.Error(t, err)
 
 	opts = testClientGenOpts()
 	// bad content in spec (HTML...)
 	opts.Spec = "https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v2.0/json/petstore.json"
-	err = GenerateClient("test", []string{}, []string{}, &opts)
+	err = GenerateClient("test", []string{}, []string{}, opts)
+	assert.Error(t, err)
+
+	opts = testClientGenOpts()
+	// no operations selected
+	opts.Spec = "https://raw.githubusercontent.com/OAI/OpenAPI-Specification/master/examples/v2.0/yaml/petstore.yaml"
+	err = GenerateClient("test", []string{}, []string{"wrongOperationID"}, opts)
 	assert.Error(t, err)
 
 	opts = testClientGenOpts()
@@ -98,12 +102,12 @@ func Test_GenerateClient(t *testing.T) {
 	}()
 	opts.Target = tft
 	opts.IsClient = true
-	DefaultSectionOpts(&opts)
+	DefaultSectionOpts(opts)
 
 	defer func() {
 		_ = os.RemoveAll(opts.Target)
 	}()
-	err = GenerateClient("test", []string{}, []string{}, &opts)
+	err = GenerateClient("test", []string{}, []string{}, opts)
 	assert.NoError(t, err)
 
 	// just checks this does not fail
@@ -117,18 +121,25 @@ func Test_GenerateClient(t *testing.T) {
 	}()
 	os.Stdout, _ = os.Create(filepath.Join(tgt, "stdout"))
 	opts.DumpData = true
-	err = GenerateClient("test", []string{}, []string{}, &opts)
+	err = GenerateClient("test", []string{}, []string{}, opts)
 	assert.NoError(t, err)
 	_, err = os.Stat(filepath.Join(tgt, "stdout"))
 	assert.NoError(t, err)
 }
 
 func TestClient(t *testing.T) {
-	targetdir, err := ioutil.TempDir(os.TempDir(), "swagger_nogo")
-	if err != nil {
-		t.Fatalf("Failed to create a test target directory: %v", err)
-	}
 	log.SetOutput(ioutil.Discard)
+	base := os.Getenv("GOPATH")
+	if base == "" {
+		base = "."
+	} else {
+		base = filepath.Join(base, "src")
+		err := os.MkdirAll(base, 0755)
+		require.NoError(t, err)
+	}
+	targetdir, err := ioutil.TempDir(base, "swagger_nogo")
+	require.NoError(t, err, "Failed to create a test target directory: %v", err)
+
 	defer func() {
 		_ = os.RemoveAll(targetdir)
 		log.SetOutput(os.Stdout)
@@ -149,7 +160,10 @@ func TestClient(t *testing.T) {
 			},
 		},
 		{
-			name:      "BaseImportDisabled",
+			name: "BaseImportDisabled",
+			prepare: func(opts *GenOpts) {
+				opts.LanguageOpts.BaseImportFunc = nil
+			},
 			wantError: false,
 		},
 		{
@@ -169,14 +183,13 @@ func TestClient(t *testing.T) {
 			opts := testClientGenOpts()
 			opts.Target = targetdir
 			opts.Spec = basicFixture
-			opts.LanguageOpts.BaseImportFunc = nil
 			opts.Template = tt.template
 
 			if tt.prepare != nil {
-				tt.prepare(&opts)
+				tt.prepare(opts)
 			}
 
-			err := GenerateClient("foo", nil, nil, &opts)
+			err := GenerateClient("foo", nil, nil, opts)
 			if tt.wantError {
 				assert.Error(t, err)
 			} else {
@@ -203,7 +216,7 @@ func TestGenClient_1518(t *testing.T) {
 	defer func() {
 		_ = os.RemoveAll(opts.Target)
 	}()
-	err := GenerateClient("client", []string{}, []string{}, &opts)
+	err := GenerateClient("client", []string{}, []string{}, opts)
 	if !assert.NoError(t, err) {
 		t.FailNow()
 	}
diff --git a/generator/discriminators_test.go b/generator/discriminators_test.go
index 767ee133..f896e07f 100644
--- a/generator/discriminators_test.go
+++ b/generator/discriminators_test.go
@@ -11,10 +11,6 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-// func init() {
-// 	loads.AddLoader(fmts.YAMLMatcher, fmts.YAMLDoc)
-// }
-
 func TestBuildDiscriminatorMap(t *testing.T) {
 	specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
 	if assert.NoError(t, err) {
@@ -25,16 +21,6 @@ func TestBuildDiscriminatorMap(t *testing.T) {
 	}
 }
 
-func opts() *GenOpts {
-	var opts GenOpts
-	opts.IncludeValidator = true
-	opts.IncludeModel = true
-	if err := opts.EnsureDefaults(); err != nil {
-		panic(err)
-	}
-	return &opts
-}
-
 func TestGenerateModel_DiscriminatorSlices(t *testing.T) {
 	specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
 	if assert.NoError(t, err) {
diff --git a/generator/generate_test.go b/generator/generate_test.go
index e47e5c9c..77863df5 100644
--- a/generator/generate_test.go
+++ b/generator/generate_test.go
@@ -2,13 +2,14 @@ package generator
 
 import (
 	"bytes"
-	"fmt"
 	"log"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"runtime"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 func TestGenerateAndTest(t *testing.T) {
@@ -31,6 +32,11 @@ func TestGenerateAndTest(t *testing.T) {
 	for name, cas := range cases {
 		var captureLog bytes.Buffer
 		log.SetOutput(&captureLog)
+		defer func() {
+			if t.Failed() {
+				t.Logf("ERROR: generation failed:\n%s", captureLog.String())
+			}
+		}()
 
 		thisCas := cas
 
@@ -44,27 +50,31 @@ func TestGenerateAndTest(t *testing.T) {
 			opts.Spec = spec
 			opts.ExcludeSpec = false
 
-			fmt.Println(opts.Target)
-
-			t.Log("generating test server")
-			err := GenerateServer("", nil, nil, &opts)
+			t.Logf("generating test server at: %s", opts.Target)
+			err := GenerateServer("", nil, nil, opts)
 			defer func() { _ = os.RemoveAll(opts.Target + "/models") }()
 			defer func() { _ = os.RemoveAll(opts.Target + "/restapi") }()
 
 			if err != nil {
-				t.Fatalf("Execute()=%s", err)
+				if !assert.NoError(t, err, "Execute()=%s", err) {
+					return
+				}
 			}
 
 			packages := filepath.Join(opts.Target, "...")
 			testPrg := filepath.Join(opts.Target, "datarace_test.go")
 
 			if p, err := exec.Command("go", "get", packages).CombinedOutput(); err != nil {
-				t.Fatalf("go get %s: %s\n%s", packages, err, p)
+				if !assert.NoError(t, err, "go get %s: %s\n%s", packages, err, p) {
+					return
+				}
 			}
 
 			t.Log("running data race test on generated server")
 			if p, err := exec.Command("go", "test", "-v", "-race", testPrg).CombinedOutput(); err != nil {
-				t.Fatalf("go test -race %s: %s\n%s", packages, err, p)
+				if !assert.NoError(t, err, "go test -race %s: %s\n%s", packages, err, p) {
+					return
+				}
 			}
 		})
 	}
diff --git a/generator/language_test.go b/generator/language_test.go
new file mode 100644
index 00000000..52170bec
--- /dev/null
+++ b/generator/language_test.go
@@ -0,0 +1,84 @@
+package generator
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestGolang_MangleFileName(t *testing.T) {
+	o := &LanguageOpts{}
+	o.Init()
+	res := o.MangleFileName("aFileEndingInOsNameWindows")
+	assert.True(t, strings.HasSuffix(res, "_windows"))
+
+	o = GoLangOpts()
+	res = o.MangleFileName("aFileEndingInOsNameWindows")
+	assert.True(t, strings.HasSuffix(res, "_windows_swagger"))
+	res = o.MangleFileName("aFileEndingInOsNameWindowsAmd64")
+	assert.True(t, strings.HasSuffix(res, "_windows_amd64_swagger"))
+	res = o.MangleFileName("aFileEndingInTest")
+	assert.True(t, strings.HasSuffix(res, "_test_swagger"))
+}
+
+func TestGolang_ManglePackage(t *testing.T) {
+	o := GoLangOpts()
+
+	for _, v := range []struct {
+		tested       string
+		expectedPath string
+		expectedName string
+	}{
+		{tested: "", expectedPath: "default", expectedName: "default"},
+		{tested: "select", expectedPath: "select_default", expectedName: "select_default"},
+		{tested: "x", expectedPath: "x", expectedName: "x"},
+		{tested: "a/b/c-d/e_f/g", expectedPath: "a/b/c-d/e_f/g", expectedName: "g"},
+		{tested: "a/b/c-d/e_f/g-h", expectedPath: "a/b/c-d/e_f/g_h", expectedName: "g_h"},
+	} {
+		res := o.ManglePackagePath(v.tested, "default")
+		assert.Equal(t, v.expectedPath, res)
+		res = o.ManglePackageName(v.tested, "default")
+		assert.Equal(t, v.expectedName, res)
+	}
+}
+
+// Go literal initializer func
+func TestGolang_SliceInitializer(t *testing.T) {
+	o := GoLangOpts()
+	goSliceInitializer := o.ArrayInitializerFunc
+
+	a0 := []interface{}{"a", "b"}
+	res, err := goSliceInitializer(a0)
+	assert.NoError(t, err)
+	assert.Equal(t, `{"a","b",}`, res)
+
+	a1 := []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}}
+	res, err = goSliceInitializer(a1)
+	assert.NoError(t, err)
+	assert.Equal(t, `{{"a","b",},{"c","d",},}`, res)
+
+	a2 := map[string]interface{}{"a": "y", "b": "z"}
+	res, err = goSliceInitializer(a2)
+	assert.NoError(t, err)
+	assert.Equal(t, `{"a":"y","b":"z",}`, res)
+
+	_, err = goSliceInitializer(struct {
+		A string `json:"a"`
+		B func() string
+	}{A: "good", B: func() string { return "" }})
+	require.Error(t, err)
+}
+
+func TestGolangInit(t *testing.T) {
+	opts := &LanguageOpts{}
+	assert.Equal(t, "", opts.baseImport("x"))
+	res, err := opts.FormatContent("x", []byte("y"))
+	require.NoError(t, err)
+	assert.Equal(t, []byte("y"), res)
+	opts = GoLangOpts()
+	o := opts
+	o.Init()
+	assert.Equal(t, opts, o)
+}
diff --git a/generator/model_test.go b/generator/model_test.go
index 10233821..76ba4d94 100644
--- a/generator/model_test.go
+++ b/generator/model_test.go
@@ -82,7 +82,8 @@ func TestGenerateModel_Sanity(t *testing.T) {
 }
 
 func TestGenerateModel_DocString(t *testing.T) {
-	templ := template.Must(template.New("docstring").Funcs(FuncMap).Parse(string(assets["docstring.gotmpl"])))
+	funcMap := FuncMapFunc(DefaultLanguageFunc())
+	templ := template.Must(template.New("docstring").Funcs(funcMap).Parse(string(assets["docstring.gotmpl"])))
 	tt := templateTest{t, templ}
 
 	var gmp GenSchema
@@ -104,7 +105,8 @@ func TestGenerateModel_DocString(t *testing.T) {
 }
 
 func TestGenerateModel_PropertyValidation(t *testing.T) {
-	templ := template.Must(template.New("propertyValidationDocString").Funcs(FuncMap).Parse(string(assets["validation/structfield.gotmpl"])))
+	funcMap := FuncMapFunc(DefaultLanguageFunc())
+	templ := template.Must(template.New("propertyValidationDocString").Funcs(funcMap).Parse(string(assets["validation/structfield.gotmpl"])))
 	tt := templateTest{t, templ}
 
 	var gmp GenSchema
@@ -949,7 +951,6 @@ func TestGenerateModel_Statix(t *testing.T) {
 		schema := definitions[k]
 		opts := opts()
 		genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
-		// spew.Dump(genModel)
 		if assert.NoError(t, err) {
 			buf := bytes.NewBuffer(nil)
 			err := templates.MustGet("model").Execute(buf, genModel)
diff --git a/generator/moreschemavalidation_test.go b/generator/moreschemavalidation_test.go
index 0dd9d597..901f90b0 100644
--- a/generator/moreschemavalidation_test.go
+++ b/generator/moreschemavalidation_test.go
@@ -152,7 +152,7 @@ var (
 	warning     []string
 )
 
-func init() {
+func initSchemaValidationTest() {
 	testedModels = make([]*modelFixture, 0, 50)
 	noLines = []string{}
 	todo = []string{`TODO`}
@@ -317,15 +317,10 @@ func TestMoreModelValidations(t *testing.T) {
 				// workaround race condition with underlying pkg: go-openapi/spec works with a global cache
 				// which does not support concurrent use for different specs.
 				//modelTestMutex.Lock()
-				specDoc, err := loads.Spec(fixtureSpec)
-				if !dassert.NoErrorf(err, "unexpected failure loading spec %s: %v", fixtureSpec, err) {
-					//modelTestMutex.Unlock()
-					t.FailNow()
-					return
-				}
 				opts := fixtureRun.FixtureOpts
+				opts.Spec = fixtureSpec
 				// this is the expanded or flattened spec
-				newSpecDoc, er0 := validateAndFlattenSpec(opts, specDoc)
+				newSpecDoc, er0 := opts.validateAndFlattenSpec()
 				if !dassert.NoErrorf(er0, "could not expand/flatten fixture %s: %v", fixtureSpec, er0) {
 					//modelTestMutex.Unlock()
 					t.FailNow()
diff --git a/generator/operation_test.go b/generator/operation_test.go
index 1c1c64c3..e680a204 100644
--- a/generator/operation_test.go
+++ b/generator/operation_test.go
@@ -28,108 +28,110 @@ import (
 	"github.com/go-openapi/loads"
 	"github.com/go-openapi/spec"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestUniqueOperationNames(t *testing.T) {
 	doc, err := loads.Spec("../fixtures/codegen/todolist.simple.yml")
-	if assert.NoError(t, err) {
-		sp := doc.Spec()
-		sp.Paths.Paths["/tasks"].Post.ID = "saveTask"
-		sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask")
-		sp.Paths.Paths["/tasks/{id}"].Put.ID = "saveTask"
-		sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask")
-		analyzed := analysis.New(sp)
-
-		ops := gatherOperations(analyzed, nil)
-		assert.Len(t, ops, 6)
-		_, exists := ops["saveTask"]
-		assert.True(t, exists)
-		_, exists = ops["PutTasksID"]
-		assert.True(t, exists)
-	}
+	require.NoError(t, err)
+
+	sp := doc.Spec()
+	sp.Paths.Paths["/tasks"].Post.ID = "saveTask"
+	sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask")
+	sp.Paths.Paths["/tasks/{id}"].Put.ID = "saveTask"
+	sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask")
+	analyzed := analysis.New(sp)
+
+	ops := gatherOperations(analyzed, nil)
+	assert.Len(t, ops, 6)
+	_, exists := ops["saveTask"]
+	assert.True(t, exists)
+	_, exists = ops["PutTasksID"]
+	assert.True(t, exists)
 }
 
 func TestEmptyOperationNames(t *testing.T) {
 	doc, err := loads.Spec("../fixtures/codegen/todolist.simple.yml")
-	if assert.NoError(t, err) {
-		sp := doc.Spec()
-		sp.Paths.Paths["/tasks"].Post.ID = ""
-		sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask")
-		sp.Paths.Paths["/tasks/{id}"].Put.ID = ""
-		sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask")
-		analyzed := analysis.New(sp)
-
-		ops := gatherOperations(analyzed, nil)
-		assert.Len(t, ops, 6)
-		_, exists := ops["PostTasks"]
-		assert.True(t, exists)
-		_, exists = ops["PutTasksID"]
-		assert.True(t, exists)
-	}
+	require.NoError(t, err)
+
+	sp := doc.Spec()
+	sp.Paths.Paths["/tasks"].Post.ID = ""
+	sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask")
+	sp.Paths.Paths["/tasks/{id}"].Put.ID = ""
+	sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask")
+	analyzed := analysis.New(sp)
+
+	ops := gatherOperations(analyzed, nil)
+	assert.Len(t, ops, 6)
+	_, exists := ops["PostTasks"]
+	assert.True(t, exists)
+	_, exists = ops["PutTasksID"]
+	assert.True(t, exists)
 }
 
 func TestMakeResponseHeader(t *testing.T) {
 	b, err := opBuilder("getTasks", "")
-	if assert.NoError(t, err) {
-		hdr := findResponseHeader(&b.Operation, 200, "X-Rate-Limit")
-		gh, er := b.MakeHeader("a", "X-Rate-Limit", *hdr)
-		if assert.NoError(t, er) {
-			assert.True(t, gh.IsPrimitive)
-			assert.Equal(t, "int32", gh.GoType)
-			assert.Equal(t, "X-Rate-Limit", gh.Name)
-		}
-	}
+	require.NoError(t, err)
+
+	hdr := findResponseHeader(&b.Operation, 200, "X-Rate-Limit")
+	gh, er := b.MakeHeader("a", "X-Rate-Limit", *hdr)
+	require.NoError(t, er)
+
+	assert.True(t, gh.IsPrimitive)
+	assert.Equal(t, "int32", gh.GoType)
+	assert.Equal(t, "X-Rate-Limit", gh.Name)
 }
 
 func TestMakeResponseHeaderDefaultValues(t *testing.T) {
 	b, err := opBuilder("getTasks", "")
-	if assert.NoError(t, err) {
-		var testCases = []struct {
-			name         string      // input
-			typeStr      string      // expected type
-			defaultValue interface{} // expected result
-		}{
-			{"Access-Control-Allow-Origin", "string", "*"},
-			{"X-Rate-Limit", "int32", nil},
-			{"X-Rate-Limit-Remaining", "int32", float64(42)},
-			{"X-Rate-Limit-Reset", "int32", "1449875311"},
-			{"X-Rate-Limit-Reset-Human", "string", "3 days"},
-			{"X-Rate-Limit-Reset-Human-Number", "string", float64(3)},
-		}
+	require.NoError(t, err)
 
-		for _, tc := range testCases {
-			// t.Logf("tc: %+v", tc)
-			hdr := findResponseHeader(&b.Operation, 200, tc.name)
-			assert.NotNil(t, hdr)
-			gh, er := b.MakeHeader("a", tc.name, *hdr)
-			if assert.NoError(t, er) {
-				assert.True(t, gh.IsPrimitive)
-				assert.Equal(t, tc.typeStr, gh.GoType)
-				assert.Equal(t, tc.name, gh.Name)
-				assert.Exactly(t, tc.defaultValue, gh.Default)
-			}
-		}
+	var testCases = []struct {
+		name         string      // input
+		typeStr      string      // expected type
+		defaultValue interface{} // expected result
+	}{
+		{"Access-Control-Allow-Origin", "string", "*"},
+		{"X-Rate-Limit", "int32", nil},
+		{"X-Rate-Limit-Remaining", "int32", float64(42)},
+		{"X-Rate-Limit-Reset", "int32", "1449875311"},
+		{"X-Rate-Limit-Reset-Human", "string", "3 days"},
+		{"X-Rate-Limit-Reset-Human-Number", "string", float64(3)},
+	}
+
+	for _, tc := range testCases {
+		// t.Logf("tc: %+v", tc)
+		hdr := findResponseHeader(&b.Operation, 200, tc.name)
+		require.NotNil(t, hdr)
+
+		gh, er := b.MakeHeader("a", tc.name, *hdr)
+		require.NoError(t, er)
+
+		assert.True(t, gh.IsPrimitive)
+		assert.Equal(t, tc.typeStr, gh.GoType)
+		assert.Equal(t, tc.name, gh.Name)
+		assert.Exactly(t, tc.defaultValue, gh.Default)
 	}
 }
 
 func TestMakeResponse(t *testing.T) {
 	b, err := opBuilder("getTasks", "")
-	if assert.NoError(t, err) {
-		resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
-		resolver.KnownDefs = make(map[string]struct{})
-		for k := range b.Doc.Spec().Definitions {
-			resolver.KnownDefs[k] = struct{}{}
-		}
-		gO, err := b.MakeResponse("a", "getTasksSuccess", true, resolver, 200, b.Operation.Responses.StatusCodeResponses[200])
-		if assert.NoError(t, err) {
-			assert.Len(t, gO.Headers, 6)
-			assert.NotNil(t, gO.Schema)
-			assert.True(t, gO.Schema.IsArray)
-			assert.NotNil(t, gO.Schema.Items)
-			assert.False(t, gO.Schema.IsAnonymous)
-			assert.Equal(t, "[]*models.Task", gO.Schema.GoType)
-		}
+	require.NoError(t, err)
+
+	resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
+	resolver.KnownDefs = make(map[string]struct{})
+	for k := range b.Doc.Spec().Definitions {
+		resolver.KnownDefs[k] = struct{}{}
 	}
+	gO, err := b.MakeResponse("a", "getTasksSuccess", true, resolver, 200, b.Operation.Responses.StatusCodeResponses[200])
+	require.NoError(t, err)
+
+	assert.Len(t, gO.Headers, 6)
+	assert.NotNil(t, gO.Schema)
+	assert.True(t, gO.Schema.IsArray)
+	assert.NotNil(t, gO.Schema.Items)
+	assert.False(t, gO.Schema.IsAnonymous)
+	assert.Equal(t, "[]*models.Task", gO.Schema.GoType)
 }
 
 func TestMakeResponse_WithAllOfSchema(t *testing.T) {
@@ -288,16 +290,18 @@ func TestRenderOperation_InstagramSearch(t *testing.T) {
 }
 
 func methodPathOpBuilder(method, path, fname string) (codeGenOpBuilder, error) {
+	log.SetOutput(ioutil.Discard)
+	defer log.SetOutput(os.Stdout)
+
 	if fname == "" {
 		fname = "../fixtures/codegen/todolist.simple.yml"
 	}
-
-	specDoc, err := loads.Spec(fname)
+	o := opts()
+	o.Spec = fname
+	specDoc, analyzed, err := o.analyzeSpec()
 	if err != nil {
 		return codeGenOpBuilder{}, err
 	}
-
-	analyzed := analysis.New(specDoc.Spec())
 	op, ok := analyzed.OperationFor(method, path)
 	if !ok {
 		return codeGenOpBuilder{}, errors.New("No operation could be found for " + method + " " + path)
@@ -316,29 +320,25 @@ func methodPathOpBuilder(method, path, fname string) (codeGenOpBuilder, error) {
 		Analyzed:      analyzed,
 		Authed:        false,
 		ExtraSchemas:  make(map[string]GenSchema),
-		GenOpts:       opts(),
+		GenOpts:       o,
 	}, nil
 }
 
 // methodPathOpBuilderWithFlatten prepares an operation build based on method and path, with spec full flattening
 func methodPathOpBuilderWithFlatten(method, path, fname string) (codeGenOpBuilder, error) {
+	log.SetOutput(ioutil.Discard)
+	defer log.SetOutput(os.Stdout)
+
 	if fname == "" {
 		fname = "../fixtures/codegen/todolist.simple.yml"
 	}
 
-	specDoc, err := loads.Spec(fname)
-	if err != nil {
-		return codeGenOpBuilder{}, err
-	}
-
 	o := opBuildGetOpts(fname, true, false) // flatten: true, minimal: false
-
-	specDoc, err = validateAndFlattenSpec(o, specDoc)
+	o.Spec = fname
+	specDoc, analyzed, err := o.analyzeSpec()
 	if err != nil {
 		return codeGenOpBuilder{}, err
 	}
-
-	analyzed := analysis.New(specDoc.Spec())
 	op, ok := analyzed.OperationFor(method, path)
 	if !ok {
 		return codeGenOpBuilder{}, errors.New("No operation could be found for " + method + " " + path)
@@ -363,31 +363,19 @@ func methodPathOpBuilderWithFlatten(method, path, fname string) (codeGenOpBuilde
 
 // opBuilderWithOpts prepares the making of an operation with spec flattening options
 func opBuilderWithOpts(name, fname string, o *GenOpts) (codeGenOpBuilder, error) {
+	log.SetOutput(ioutil.Discard)
+	defer log.SetOutput(os.Stdout)
+
 	if fname == "" {
 		// default fixture
 		fname = "../fixtures/codegen/todolist.simple.yml"
 	}
 
-	if !filepath.IsAbs(fname) {
-		cwd, _ := os.Getwd()
-		fname = filepath.Join(cwd, fname)
-	}
-
-	specDoc, err := loads.Spec(fname)
-	if err != nil {
-		return codeGenOpBuilder{}, err
-	}
 	o.Spec = fname
-
-	log.SetOutput(ioutil.Discard)
-	defer log.SetOutput(os.Stdout)
-	specDoc, err = validateAndFlattenSpec(o, specDoc)
+	specDoc, analyzed, err := o.analyzeSpec()
 	if err != nil {
 		return codeGenOpBuilder{}, err
 	}
-	log.SetOutput(os.Stdout)
-
-	analyzed := analysis.New(specDoc.Spec())
 
 	method, path, op, ok := analyzed.OperationForName(name)
 	if !ok {
@@ -408,19 +396,21 @@ func opBuilderWithOpts(name, fname string, o *GenOpts) (codeGenOpBuilder, error)
 		Analyzed:      analyzed,
 		Authed:        false,
 		ExtraSchemas:  make(map[string]GenSchema),
-		GenOpts:       o, // opts()??
+		GenOpts:       o,
 	}, nil
 }
 
 func opBuildGetOpts(specName string, withFlatten bool, withMinimalFlatten bool) (opts *GenOpts) {
 	opts = &GenOpts{}
-	if erd := opts.EnsureDefaults(); erd != nil {
-		panic("Cannot initialize GenOpts")
-	}
 	opts.ValidateSpec = true
-	opts.FlattenOpts.Expand = !withFlatten
-	opts.FlattenOpts.Minimal = withMinimalFlatten
+	opts.FlattenOpts = &analysis.FlattenOpts{
+		Expand:  !withFlatten,
+		Minimal: withMinimalFlatten,
+	}
 	opts.Spec = specName
+	if err := opts.EnsureDefaults(); err != nil {
+		panic("Cannot initialize GenOpts")
+	}
 	return
 }
 
@@ -430,6 +420,14 @@ func opBuilderWithFlatten(name, fname string) (codeGenOpBuilder, error) {
 	return opBuilderWithOpts(name, fname, o)
 }
 
+/*
+// opBuilderWithMinimalFlatten prepares the making of an operation with spec minimal flattening prior to rendering
+func opBuilderWithMinimalFlatten(name, fname string) (codeGenOpBuilder, error) {
+	o := opBuildGetOpts(fname, true, true) // flatten: true, minimal: true
+	return opBuilderWithOpts(name, fname, o)
+}
+*/
+
 // opBuilderWithExpand prepares the making of an operation with spec expansion prior to rendering
 func opBuilderWithExpand(name, fname string) (codeGenOpBuilder, error) {
 	o := opBuildGetOpts(fname, false, false) // flatten: false => expand
@@ -793,7 +791,7 @@ func TestGenClientIssue890_ValidationTrueFlatteningTrue(t *testing.T) {
 	opts.FlattenOpts.Minimal = false
 	// Testing this is enough as there is only one operation which is specified as $ref.
 	// If this doesn't get resolved then there will be an error definitely.
-	assert.NoError(t, GenerateClient("foo", nil, nil, &opts))
+	assert.NoError(t, GenerateClient("foo", nil, nil, opts))
 }
 
 func TestGenServerIssue890_ValidationFalseFlattenTrue(t *testing.T) {
@@ -854,7 +852,7 @@ func TestGenClientIssue890_ValidationFalseFlatteningTrue(t *testing.T) {
 	opts.FlattenOpts.Minimal = false
 	// Testing this is enough as there is only one operation which is specified as $ref.
 	// If this doesn't get resolved then there will be an error definitely.
-	assert.NoError(t, GenerateClient("foo", nil, nil, &opts))
+	assert.NoError(t, GenerateClient("foo", nil, nil, opts))
 }
 
 func TestGenServerIssue890_ValidationFalseFlattenFalse(t *testing.T) {
@@ -903,7 +901,7 @@ func TestGenClientIssue890_ValidationFalseFlattenFalse(t *testing.T) {
 	// Testing this is enough as there is only one operation which is specified as $ref.
 	// If this doesn't get resolved then there will be an error definitely.
 	// New: Now if flatten is false, expand takes over so server generation should resume normally
-	assert.NoError(t, GenerateClient("foo", nil, nil, &opts))
+	assert.NoError(t, GenerateClient("foo", nil, nil, opts))
 }
 
 func TestGenServerIssue890_ValidationTrueFlattenFalse(t *testing.T) {
@@ -948,7 +946,7 @@ func TestGenServerWithTemplate(t *testing.T) {
 		wantError bool
 	}{
 		{
-			name: "None_existing_contributor_tempalte",
+			name: "None_existing_contributor_template",
 			opts: &GenOpts{
 				Spec:              filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"),
 				IncludeModel:      true,
@@ -1021,7 +1019,7 @@ func TestGenClientIssue890_ValidationTrueFlattenFalse(t *testing.T) {
 	// Testing this is enough as there is only one operation which is specified as $ref.
 	// If this doesn't get resolved then there will be an error definitely.
 	// same here: now if flatten doesn't resume, expand takes over
-	assert.NoError(t, GenerateClient("foo", nil, nil, &opts))
+	assert.NoError(t, GenerateClient("foo", nil, nil, opts))
 }
 
 // This tests that securityDefinitions generate stable code
@@ -1383,12 +1381,12 @@ func TestGenServer_StrictAdditionalProperties(t *testing.T) {
 }
 
 func makeClientTimeoutNameTest() []struct {
-	seenIds  map[string]bool
+	seenIds  map[string]interface{}
 	name     string
 	expected string
 } {
 	return []struct {
-		seenIds  map[string]bool
+		seenIds  map[string]interface{}
 		name     string
 		expected string
 	}{
@@ -1398,14 +1396,14 @@ func makeClientTimeoutNameTest() []struct {
 			expected: "witness",
 		},
 		{
-			seenIds: map[string]bool{
+			seenIds: map[string]interface{}{
 				"id": true,
 			},
 			name:     "timeout",
 			expected: "timeout",
 		},
 		{
-			seenIds: map[string]bool{
+			seenIds: map[string]interface{}{
 				"timeout":        true,
 				"requesttimeout": true,
 			},
@@ -1413,7 +1411,7 @@ func makeClientTimeoutNameTest() []struct {
 			expected: "httpRequestTimeout",
 		},
 		{
-			seenIds: map[string]bool{
+			seenIds: map[string]interface{}{
 				"timeout":            true,
 				"requesttimeout":     true,
 				"httprequesttimeout": true,
@@ -1425,7 +1423,7 @@ func makeClientTimeoutNameTest() []struct {
 			expected: "operTimeout",
 		},
 		{
-			seenIds: map[string]bool{
+			seenIds: map[string]interface{}{
 				"timeout":            true,
 				"requesttimeout":     true,
 				"httprequesttimeout": true,
@@ -1445,8 +1443,36 @@ func TestRenameTimeout(t *testing.T) {
 	for i, toPin := range makeClientTimeoutNameTest() {
 		testCase := toPin
 		t.Run(testCase.name, func(t *testing.T) {
-			//t.Parallel()
+			t.Parallel()
 			assert.Equalf(t, testCase.expected, renameTimeout(testCase.seenIds, testCase.name), "unexpected deconflicting value [%d]", i)
 		})
 	}
 }
+
+func testInvalidParams() map[string]spec.Parameter {
+	return map[string]spec.Parameter{
+		"query#param1": *spec.QueryParam("param1"),
+		"path#param1":  *spec.PathParam("param1"),
+		"body#param1":  *spec.BodyParam("param1", &spec.Schema{}),
+	}
+}
+
+func TestParamMappings(t *testing.T) {
+	// Test deconfliction of duplicate param names across param locations
+	mappings, _ := paramMappings(testInvalidParams())
+	require.Contains(t, mappings, "query")
+	require.Contains(t, mappings, "path")
+	require.Contains(t, mappings, "body")
+	q := mappings["query"]
+	p := mappings["path"]
+	b := mappings["body"]
+	require.Len(t, q, 1)
+	require.Len(t, p, 1)
+	require.Len(t, b, 1)
+	require.Containsf(t, q, "param1", "unexpected content of %#v", q)
+	require.Containsf(t, p, "param1", "unexpected content of %#v", p)
+	require.Containsf(t, b, "param1", "unexpected content of %#v", b)
+	assert.Equalf(t, "QueryParam1", q["param1"], "unexpected content of %#v", q["param1"])
+	assert.Equalf(t, "PathParam1", p["param1"], "unexpected content of %#v", p["param1"])
+	assert.Equalf(t, "BodyParam1", b["param1"], "unexpected content of %#v", b["param1"])
+}
diff --git a/generator/parameter_test.go b/generator/parameter_test.go
index 89f3ce58..6fd66564 100644
--- a/generator/parameter_test.go
+++ b/generator/parameter_test.go
@@ -28,68 +28,60 @@ import (
 	"github.com/go-openapi/spec"
 	"github.com/go-openapi/swag"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestBodyParams(t *testing.T) {
 	b, err := opBuilder("updateTask", "../fixtures/codegen/todolist.bodyparams.yml")
-
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
+	require.NoError(t, err)
 
 	_, _, op, ok := b.Analyzed.OperationForName("updateTask")
-	if assert.True(t, ok) && assert.NotNil(t, op) {
-		resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
-		resolver.KnownDefs = make(map[string]struct{})
-		for k := range b.Doc.Spec().Definitions {
-			resolver.KnownDefs[k] = struct{}{}
-		}
-		for _, param := range op.Parameters {
-			if param.Name == "body" {
-				gp, perr := b.MakeParameter("a", resolver, param, nil)
-				if assert.NoError(t, perr) {
-					assert.True(t, gp.IsBodyParam())
-					if assert.NotNil(t, gp.Schema) {
-						assert.True(t, gp.Schema.IsComplexObject)
-						assert.False(t, gp.Schema.IsAnonymous)
-						assert.Equal(t, "models.Task", gp.Schema.GoType)
-					}
-				}
-			}
+
+	require.True(t, ok)
+	require.NotNil(t, op)
+	resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
+	resolver.KnownDefs = make(map[string]struct{})
+	for k := range b.Doc.Spec().Definitions {
+		resolver.KnownDefs[k] = struct{}{}
+	}
+	for _, param := range op.Parameters {
+		if param.Name == "body" {
+			gp, perr := b.MakeParameter("a", resolver, param, nil)
+			require.NoError(t, perr)
+			assert.True(t, gp.IsBodyParam())
+			require.NotNil(t, gp.Schema)
+			assert.True(t, gp.Schema.IsComplexObject)
+			assert.False(t, gp.Schema.IsAnonymous)
+			assert.Equal(t, "models.Task", gp.Schema.GoType)
 		}
 	}
 
 	b, err = opBuilder("createTask", "../fixtures/codegen/todolist.bodyparams.yml")
-
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
+	require.NoError(t, err)
 
 	_, _, op, ok = b.Analyzed.OperationForName("createTask")
-	if assert.True(t, ok) && assert.NotNil(t, op) {
-		resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
-		resolver.KnownDefs = make(map[string]struct{})
-		for k := range b.Doc.Spec().Definitions {
-			resolver.KnownDefs[k] = struct{}{}
-		}
-		for _, param := range op.Parameters {
-			if param.Name == "body" {
-				gp, err := b.MakeParameter("a", resolver, param, nil)
-				if assert.NoError(t, err) {
-					assert.True(t, gp.IsBodyParam())
-					if assert.NotNil(t, gp.Schema) {
-						assert.True(t, gp.Schema.IsComplexObject)
-						assert.False(t, gp.Schema.IsAnonymous)
-						assert.Equal(t, "CreateTaskBody", gp.Schema.GoType)
-
-						gpe, ok := b.ExtraSchemas["CreateTaskBody"]
-						assert.True(t, ok)
-						assert.True(t, gpe.IsComplexObject)
-						assert.False(t, gpe.IsAnonymous)
-						assert.Equal(t, "CreateTaskBody", gpe.GoType)
-					}
-				}
-			}
+	require.True(t, ok)
+	require.NotNil(t, op)
+	resolver = &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
+	resolver.KnownDefs = make(map[string]struct{})
+	for k := range b.Doc.Spec().Definitions {
+		resolver.KnownDefs[k] = struct{}{}
+	}
+	for _, param := range op.Parameters {
+		if param.Name == "body" {
+			gp, err := b.MakeParameter("a", resolver, param, nil)
+			require.NoError(t, err)
+			assert.True(t, gp.IsBodyParam())
+			require.NotNil(t, gp.Schema)
+			assert.True(t, gp.Schema.IsComplexObject)
+			assert.False(t, gp.Schema.IsAnonymous)
+			assert.Equal(t, "CreateTaskBody", gp.Schema.GoType)
+
+			gpe, ok := b.ExtraSchemas["CreateTaskBody"]
+			assert.True(t, ok)
+			assert.True(t, gpe.IsComplexObject)
+			assert.False(t, gpe.IsAnonymous)
+			assert.Equal(t, "CreateTaskBody", gpe.GoType)
 		}
 	}
 }
@@ -108,16 +100,11 @@ var arrayFormParams = []paramTestContext{
 
 func TestFormArrayParams(t *testing.T) {
 	b, err := opBuilder("arrayFormParams", "../fixtures/codegen/todolist.arrayform.yml")
-
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
+	require.NoError(t, err)
 
 	for _, v := range arrayFormParams {
 		v.B = b
-		if !v.assertParameter(t) {
-			t.FailNow()
-		}
+		require.True(t, v.assertParameter(t))
 	}
 }
 
@@ -135,16 +122,11 @@ var arrayQueryParams = []paramTestContext{
 
 func TestQueryArrayParams(t *testing.T) {
 	b, err := opBuilder("arrayQueryParams", "../fixtures/codegen/todolist.arrayquery.yml")
-
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
+	require.NoError(t, err)
 
 	for _, v := range arrayQueryParams {
 		v.B = b
-		if !v.assertParameter(t) {
-			t.FailNow()
-		}
+		require.True(t, v.assertParameter(t))
 	}
 }
 
@@ -161,15 +143,11 @@ var simplePathParams = []paramTestContext{
 
 func TestSimplePathParams(t *testing.T) {
 	b, err := opBuilder("simplePathParams", "../fixtures/codegen/todolist.simplepath.yml")
+	require.NoError(t, err)
 
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
 	for _, v := range simplePathParams {
 		v.B = b
-		if !v.assertParameter(t) {
-			t.FailNow()
-		}
+		require.True(t, v.assertParameter(t))
 	}
 }
 
@@ -187,15 +165,11 @@ var simpleHeaderParams = []paramTestContext{
 
 func TestSimpleHeaderParams(t *testing.T) {
 	b, err := opBuilder("simpleHeaderParams", "../fixtures/codegen/todolist.simpleheader.yml")
+	require.NoError(t, err)
 
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
 	for _, v := range simpleHeaderParams {
 		v.B = b
-		if !v.assertParameter(t) {
-			t.FailNow()
-		}
+		require.True(t, v.assertParameter(t))
 	}
 }
 
@@ -213,15 +187,11 @@ var simpleFormParams = []paramTestContext{
 
 func TestSimpleFormParams(t *testing.T) {
 	b, err := opBuilder("simpleFormParams", "../fixtures/codegen/todolist.simpleform.yml")
+	require.NoError(t, err)
 
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
 	for _, v := range simpleFormParams {
 		v.B = b
-		if !v.assertParameter(t) {
-			t.FailNow()
-		}
+		require.True(t, v.assertParameter(t))
 	}
 }
 
@@ -239,15 +209,11 @@ var simpleQueryParams = []paramTestContext{
 
 func TestSimpleQueryParamsAST(t *testing.T) {
 	b, err := opBuilder("simpleQueryParams", "../fixtures/codegen/todolist.simplequery.yml")
+	require.NoError(t, err)
 
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
 	for _, v := range simpleQueryParams {
 		v.B = b
-		if !v.assertParameter(t) {
-			t.FailNow()
-		}
+		require.True(t, v.assertParameter(t))
 	}
 }
 
@@ -460,14 +426,10 @@ func TestGenParameters_Simple(t *testing.T) {
 	}()
 
 	b, err := opBuilder("getSearch", "../fixtures/bugs/163/swagger.yml")
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
+	require.NoError(t, err)
 	for _, v := range bug163Properties {
 		v.B = b
-		if !v.assertParameter(t) {
-			t.FailNow()
-		}
+		require.True(t, v.assertParameter(t))
 	}
 }
 
@@ -478,25 +440,22 @@ func TestGenParameter_Issue163(t *testing.T) {
 	}()
 
 	b, err := opBuilder("getSearch", "../fixtures/bugs/163/swagger.yml")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			buf := bytes.NewBuffer(nil)
-			opts := opts()
-			err := templates.MustGet("serverParameter").Execute(buf, op)
-			if assert.NoError(t, err) {
-				ff, err := opts.LanguageOpts.FormatContent("get_search_parameters.go", buf.Bytes())
-				if assert.NoError(t, err) {
-					res := string(ff)
-					// NOTE(fredbi): removed default values resolution from private details (defaults are resolved in NewXXXParams())
-					assertInCode(t, "stringTypeInQueryDefault = string(\"qsValue\")", res)
-					assertInCode(t, "StringTypeInQuery: &stringTypeInQueryDefault", res)
-				} else {
-					fmt.Println(buf.String())
-				}
-			}
-		}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	buf := bytes.NewBuffer(nil)
+	opts := opts()
+	err = templates.MustGet("serverParameter").Execute(buf, op)
+	require.NoError(t, err)
+	ff, err := opts.LanguageOpts.FormatContent("get_search_parameters.go", buf.Bytes())
+	if err != nil {
+		fmt.Println(buf.String())
 	}
+	require.NoError(t, err)
+	res := string(ff)
+	// NOTE(fredbi): removed default values resolution from private details (defaults are resolved in NewXXXParams())
+	assertInCode(t, "stringTypeInQueryDefault = string(\"qsValue\")", res)
+	assertInCode(t, "StringTypeInQuery: &stringTypeInQueryDefault", res)
 }
 
 func TestGenParameter_Issue195(t *testing.T) {
@@ -931,29 +890,24 @@ func TestGenParameter_Issue710(t *testing.T) {
 }
 
 func TestGenParameter_Issue776_LocalFileRef(t *testing.T) {
-	//spec.Debug = true
 	log.SetOutput(ioutil.Discard)
 	defer func() {
-		//spec.Debug = false
 		log.SetOutput(os.Stdout)
 	}()
 	b, err := opBuilderWithFlatten("GetItem", "../fixtures/bugs/776/param.yaml")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			var buf bytes.Buffer
-			opts := opts()
-			if assert.NoError(t, templates.MustGet("serverParameter").Execute(&buf, op)) {
-				ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
-				if assert.NoError(t, err) {
-					assertInCode(t, "Body *models.Item", string(ff))
-					assertNotInCode(t, "type GetItemParamsBody struct", string(ff))
-				} else {
-					fmt.Println(buf.String())
-				}
-			}
-		}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	var buf bytes.Buffer
+	opts := opts()
+	require.NoError(t, templates.MustGet("serverParameter").Execute(&buf, op))
+	ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
+	if err != nil {
+		fmt.Println(buf.String())
 	}
+	require.NoError(t, err)
+	assertInCode(t, "Body *models.Item", string(ff))
+	assertNotInCode(t, "type GetItemParamsBody struct", string(ff))
 
 }
 
diff --git a/generator/response_test.go b/generator/response_test.go
index 7a9678c7..5840ed71 100644
--- a/generator/response_test.go
+++ b/generator/response_test.go
@@ -25,6 +25,7 @@ import (
 
 	"github.com/go-openapi/spec"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestSimpleResponseRender(t *testing.T) {
@@ -316,51 +317,43 @@ func TestGenResponses_Issue718_NotRequired(t *testing.T) {
 
 func TestGenResponses_Issue718_Required(t *testing.T) {
 	b, err := opBuilder("doEmpty", "../fixtures/codegen/todolist.simple.yml")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			var buf bytes.Buffer
-			opts := opts()
-			if assert.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op)) {
-				ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
-				if assert.NoError(t, err) {
-					assertInCode(t, "if payload == nil", string(ff))
-					assertInCode(t, "payload = make([]models.Foo, 0, 50)", string(ff))
-				} else {
-					fmt.Println(buf.String())
-				}
-			}
-		}
-	}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	var buf bytes.Buffer
+	opts := opts()
+	require.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
+	ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
+	if err != nil {
+		fmt.Println(buf.String())
+	}
+	require.NoError(t, err)
+	assertInCode(t, "if payload == nil", string(ff))
+	assertInCode(t, "payload = make([]models.Foo, 0, 50)", string(ff))
 }
 
 // Issue776 includes references that span multiple files. Flattening or Expanding is required
 func TestGenResponses_Issue776_Spec(t *testing.T) {
-	//spec.Debug = true
 	log.SetOutput(ioutil.Discard)
 	defer func() {
 		log.SetOutput(os.Stdout)
-		//spec.Debug = false
 	}()
 
 	b, err := opBuilderWithFlatten("GetItem", "../fixtures/bugs/776/spec.yaml")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			var buf bytes.Buffer
-			opts := opts()
-			if assert.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op)) {
-				ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
-				if assert.NoError(t, err) {
-					// This should be models.Item if flat works correctly
-					assertInCode(t, "Payload *models.Item", string(ff))
-					assertNotInCode(t, "type GetItemOKBody struct", string(ff))
-				} else {
-					fmt.Println(buf.String())
-				}
-			}
-		}
-	}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	var buf bytes.Buffer
+	opts := opts()
+	require.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
+	ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
+	if err != nil {
+		fmt.Println(buf.String())
+	}
+	require.NoError(t, err)
+	// This should be models.Item if flat works correctly
+	assertInCode(t, "Payload *models.Item", string(ff))
+	assertNotInCode(t, "type GetItemOKBody struct", string(ff))
 }
 
 func TestGenResponses_Issue776_SwaggerTemplate(t *testing.T) {
@@ -372,96 +365,83 @@ func TestGenResponses_Issue776_SwaggerTemplate(t *testing.T) {
 	}()
 
 	b, err := opBuilderWithFlatten("getHealthy", "../fixtures/bugs/776/swagger-template.yml")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			var buf bytes.Buffer
-			opts := opts()
-			if assert.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op)) {
-				ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
-				if assert.NoError(t, err) {
-					assertInCode(t, "Payload *models.Error", string(ff))
-				} else {
-					fmt.Println(buf.String())
-				}
-			}
-		}
-	}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	var buf bytes.Buffer
+	opts := opts()
+	require.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
+	ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
+	if err != nil {
+		fmt.Println(buf.String())
+	}
+	require.NoError(t, err)
+	assertInCode(t, "Payload *models.Error", string(ff))
 }
 
 func TestIssue846(t *testing.T) {
 	// do it 8 times, to ensure it's always in the same order
 	for i := 0; i < 8; i++ {
 		b, err := opBuilder("getFoo", "../fixtures/bugs/846/swagger.yml")
-		if assert.NoError(t, err) {
-			op, err := b.MakeOperation()
-			if assert.NoError(t, err) {
-				var buf bytes.Buffer
-				opts := opts()
-				if assert.NoError(t, templates.MustGet("clientResponse").Execute(&buf, op)) {
-					ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
-					if assert.NoError(t, err) {
-						// sorted by code
-						assert.Regexp(t, "(?s)"+
-							"GetFooOK struct.+"+
-							"GetFooNotFound struct.+"+
-							"GetFooInternalServerError struct", string(ff))
-						// sorted by name
-						assert.Regexp(t, "(?s)"+
-							"GetFooInternalServerErrorBody struct.+"+
-							"GetFooNotFoundBody struct.+"+
-							"GetFooOKBody struct", string(ff))
-					} else {
-						fmt.Println(buf.String())
-					}
-				}
-			}
+		require.NoError(t, err)
+		op, err := b.MakeOperation()
+		require.NoError(t, err)
+		var buf bytes.Buffer
+		opts := opts()
+		require.NoError(t, templates.MustGet("clientResponse").Execute(&buf, op))
+		ff, err := opts.LanguageOpts.FormatContent("do_empty_responses.go", buf.Bytes())
+		if err != nil {
+			fmt.Println(buf.String())
 		}
+		require.NoError(t, err)
+		// sorted by code
+		assert.Regexp(t, "(?s)"+
+			"GetFooOK struct.+"+
+			"GetFooNotFound struct.+"+
+			"GetFooInternalServerError struct", string(ff))
+		// sorted by name
+		assert.Regexp(t, "(?s)"+
+			"GetFooInternalServerErrorBody struct.+"+
+			"GetFooNotFoundBody struct.+"+
+			"GetFooOKBody struct", string(ff))
 	}
 }
 
 func TestIssue881(t *testing.T) {
 	b, err := opBuilder("getFoo", "../fixtures/bugs/881/swagger.yml")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			var buf bytes.Buffer
-			assert.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
-		}
-	}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	var buf bytes.Buffer
+	require.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
 }
 
 func TestIssue881Deep(t *testing.T) {
 	b, err := opBuilder("getFoo", "../fixtures/bugs/881/deep.yml")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			var buf bytes.Buffer
-			assert.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
-		}
-	}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	var buf bytes.Buffer
+	require.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
 }
 
 func TestGenResponses_XGoName(t *testing.T) {
 	b, err := opBuilder("putTesting", "../fixtures/specs/response_name.json")
-	if assert.NoError(t, err) {
-		op, err := b.MakeOperation()
-		if assert.NoError(t, err) {
-			var buf bytes.Buffer
-			opts := opts()
-			if assert.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op)) {
-				ff, err := opts.LanguageOpts.FormatContent("put_testing_responses.go", buf.Bytes())
-				if assert.NoError(t, err) {
-					assertInCode(t, "const PutTestingAlternateNameCode int =", string(ff))
-					assertInCode(t, "type PutTestingAlternateName struct {", string(ff))
-					assertInCode(t, "func NewPutTestingAlternateName() *PutTestingAlternateName {", string(ff))
-					assertInCode(t, "func (o *PutTestingAlternateName) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {", string(ff))
-				} else {
-					fmt.Println(buf.String())
-				}
-			}
-		}
-	}
+	require.NoError(t, err)
+	op, err := b.MakeOperation()
+	require.NoError(t, err)
+	var buf bytes.Buffer
+	opts := opts()
+	require.NoError(t, templates.MustGet("serverResponses").Execute(&buf, op))
+	ff, err := opts.LanguageOpts.FormatContent("put_testing_responses.go", buf.Bytes())
+	if err != nil {
+		fmt.Println(buf.String())
+	}
+	require.NoError(t, err)
+	assertInCode(t, "const PutTestingAlternateNameCode int =", string(ff))
+	assertInCode(t, "type PutTestingAlternateName struct {", string(ff))
+	assertInCode(t, "func NewPutTestingAlternateName() *PutTestingAlternateName {", string(ff))
+	assertInCode(t, "func (o *PutTestingAlternateName) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {", string(ff))
 }
 
 func TestGenResponses_Issue892(t *testing.T) {
diff --git a/generator/schemavalidation_test.go b/generator/schemavalidation_test.go
index ca17f764..107346ca 100644
--- a/generator/schemavalidation_test.go
+++ b/generator/schemavalidation_test.go
@@ -17,7 +17,6 @@ package generator
 import (
 	"bytes"
 	"fmt"
-	"log"
 	"regexp"
 	"testing"
 
@@ -26,9 +25,7 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func init() {
-	log.SetFlags(log.LstdFlags | log.Lshortfile)
-}
+// testing utilities for codegen assertions
 
 func reqm(str string) *regexp.Regexp {
 	return regexp.MustCompile(regexp.QuoteMeta(str))
diff --git a/generator/server_test.go b/generator/server_test.go
index f52cad86..5d4b0e34 100644
--- a/generator/server_test.go
+++ b/generator/server_test.go
@@ -21,35 +21,6 @@ import (
 
 const invalidSpecExample = "../fixtures/bugs/825/swagger.yml"
 
-// Perform common initialization of template repository before running tests.
-// This allows to run tests unitarily (e.g. go test -run xxx ).
-func TestMain(m *testing.M) {
-	templates.LoadDefaults()
-	os.Exit(m.Run())
-}
-
-func testGenOpts() (g GenOpts) {
-	g.Target = "."
-	g.APIPackage = defaultAPIPackage
-	g.ModelPackage = defaultModelPackage
-	g.ServerPackage = defaultServerPackage
-	g.ClientPackage = defaultClientPackage
-	g.Principal = ""
-	g.DefaultScheme = "http"
-	g.IncludeModel = true
-	g.IncludeValidator = true
-	g.IncludeHandler = true
-	g.IncludeParameters = true
-	g.IncludeResponses = true
-	g.IncludeMain = false
-	g.IncludeSupport = true
-	g.ExcludeSpec = true
-	g.TemplateDir = ""
-	g.DumpData = false
-	_ = g.EnsureDefaults()
-	return
-}
-
 func testAppGenerator(t testing.TB, specPath, name string) (*appGenerator, error) {
 	specDoc, err := loads.Spec(specPath)
 	if !assert.NoError(t, err) {
@@ -89,7 +60,7 @@ func testAppGenerator(t testing.TB, specPath, name string) (*appGenerator, error
 		DefaultScheme:   "http",
 		DefaultProduces: runtime.JSONMime,
 		DefaultConsumes: runtime.JSONMime,
-		GenOpts:         &opts,
+		GenOpts:         opts,
 	}, nil
 }
 
@@ -161,7 +132,7 @@ func TestServer_InvalidSpec(t *testing.T) {
 	opts := testGenOpts()
 	opts.Spec = invalidSpecExample
 	opts.ValidateSpec = true
-	assert.Error(t, GenerateServer("foo", nil, nil, &opts))
+	assert.Error(t, GenerateServer("foo", nil, nil, opts))
 }
 
 func TestServer_TrailingSlash(t *testing.T) {
@@ -481,7 +452,7 @@ func TestServer_Issue1746(t *testing.T) {
 	opts.Spec = filepath.Join("..", "..", "fixtures", "bugs", "1746", "fixture-1746.yaml")
 	tgtSpec := regexp.QuoteMeta(filepath.Join("..", "..", opts.Spec))
 
-	err = GenerateServer("", nil, nil, &opts)
+	err = GenerateServer("", nil, nil, opts)
 	assert.NoError(t, err)
 	gulp, err := ioutil.ReadFile(filepath.Join("x", "restapi", "configure_example_swagger_server.go"))
 	assert.NoError(t, err)
diff --git a/generator/shared_test.go b/generator/shared_test.go
index e1b9f3cb..c54592d4 100644
--- a/generator/shared_test.go
+++ b/generator/shared_test.go
@@ -8,15 +8,66 @@ import (
 	"path"
 	"path/filepath"
 	"runtime"
-	"strings"
 	"testing"
 
-	"github.com/go-openapi/analysis"
 	"github.com/go-openapi/loads"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
-const testPath = "a/b/c"
+const (
+	defaultAPIPackage    = "operations"
+	defaultClientPackage = "client"
+	defaultModelPackage  = "models"
+	defaultServerPackage = "restapi"
+)
+
+// Perform common initialization of template repository before running tests.
+// This allows to run tests unitarily (e.g. go test -run xxx ).
+func TestMain(m *testing.M) {
+	// initializations to run tests in this package
+	log.SetFlags(log.LstdFlags | log.Lshortfile)
+	templates.LoadDefaults()
+	initSchemaValidationTest()
+	os.Exit(m.Run())
+}
+
+func opts() *GenOpts {
+	var opts GenOpts
+	opts.IncludeValidator = true
+	opts.IncludeModel = true
+	if err := opts.EnsureDefaults(); err != nil {
+		panic(err)
+	}
+	return &opts
+}
+
+func testGenOpts() *GenOpts {
+	g := &GenOpts{}
+	g.Target = "."
+	g.APIPackage = defaultAPIPackage
+	g.ModelPackage = defaultModelPackage
+	g.ServerPackage = defaultServerPackage
+	g.ClientPackage = defaultClientPackage
+	g.Principal = ""
+	g.DefaultScheme = "http"
+	g.IncludeModel = true
+	g.IncludeValidator = true
+	g.IncludeModel = true
+	g.IncludeHandler = true
+	g.IncludeParameters = true
+	g.IncludeResponses = true
+	g.IncludeMain = false
+	g.IncludeSupport = true
+	g.ExcludeSpec = true
+	g.TemplateDir = ""
+	g.DumpData = false
+
+	if err := g.EnsureDefaults(); err != nil {
+		panic(err)
+	}
+	return g
+}
 
 // TODO: there is a catch, since these methods are sensitive
 // to the CWD of the current swagger command (or go
@@ -27,12 +78,15 @@ const testPath = "a/b/c"
 // Windows style path is difficult to test on unix
 // since the filepath pkg is platform dependent
 func TestShared_CheckOpts(t *testing.T) {
+	testPath := filepath.Join("a", "b", "b")
+
 	log.SetOutput(ioutil.Discard)
 	defer log.SetOutput(os.Stdout)
 
 	var opts = new(GenOpts)
 	_ = opts.EnsureDefaults()
 	cwd, _ := os.Getwd()
+	opts.Spec = "../fixtures/codegen/simplesearch.yml"
 
 	opts.Target = filepath.Join(".", "a", "b", "c")
 	opts.ServerPackage = filepath.Join(cwd, "a", "b", "c")
@@ -41,26 +95,46 @@ func TestShared_CheckOpts(t *testing.T) {
 
 	opts.Target = filepath.Join(cwd, "a", "b", "c")
 	opts.ServerPackage = testPath
+	opts.Spec = filepath.Join(cwd, "nowhere", "swagger.yaml")
 	err = opts.CheckOpts()
-	assert.NoError(t, err)
+	assert.Error(t, err)
 
 	opts.Target = filepath.Join(cwd, "a", "b", "c")
 	opts.ServerPackage = testPath
-	opts.Spec = "https:/ab/c"
+	opts.Spec = "https://ab/c"
 	err = opts.CheckOpts()
 	assert.NoError(t, err)
 
 	opts.Target = filepath.Join(cwd, "a", "b", "c")
 	opts.ServerPackage = testPath
-	opts.Spec = "http:/ab/c"
+	opts.Spec = "http://ab/c"
 	err = opts.CheckOpts()
 	assert.NoError(t, err)
 
 	opts.Target = filepath.Join("a", "b", "c")
 	opts.ServerPackage = testPath
-	opts.Spec = filepath.Join(cwd, "x")
+	opts.Spec = filepath.Join(cwd, "..", "fixtures", "codegen", "swagger-codegen-tests.json")
 	err = opts.CheckOpts()
 	assert.NoError(t, err)
+
+	opts.Target = filepath.Join("a", "b", "c")
+	opts.ServerPackage = testPath
+	opts.Spec = filepath.Join("..", "fixtures", "codegen", "swagger-codegen-tests.json")
+	err = opts.CheckOpts()
+	assert.NoError(t, err)
+
+	opts = nil
+	err = opts.CheckOpts()
+	assert.Error(t, err)
+}
+
+func TestShared_EnsureDefaults(t *testing.T) {
+	opts := &GenOpts{}
+	_ = opts.EnsureDefaults()
+	assert.True(t, opts.defaultsEnsured)
+	opts.DefaultConsumes = "https"
+	_ = opts.EnsureDefaults()
+	assert.Equal(t, "https", opts.DefaultConsumes)
 }
 
 // TargetPath and SpecPath are used in server.gotmpl
@@ -416,7 +490,6 @@ func TestShared_LoadTemplate(t *testing.T) {
 	}
 
 	buf, err := opts.render(&tplOpts, nil)
-	//spew.Dump(err)
 	assert.Error(t, err, "Error should be handled here")
 	assert.Contains(t, err.Error(), "open File")
 	assert.Contains(t, err.Error(), "error while opening")
@@ -424,7 +497,6 @@ func TestShared_LoadTemplate(t *testing.T) {
 
 	opts.TemplateDir = filepath.Join(".", "myTemplateDir")
 	buf, err = opts.render(&tplOpts, nil)
-	//spew.Dump(err)
 	assert.Error(t, err, "Error should be handled here")
 	assert.Contains(t, err.Error(), "open "+filepath.Join("myTemplateDir", "File"))
 	assert.Contains(t, err.Error(), "error while opening")
@@ -432,139 +504,59 @@ func TestShared_LoadTemplate(t *testing.T) {
 
 }
 
-func TestShared_Issue1429(t *testing.T) {
-	log.SetOutput(ioutil.Discard)
-	defer log.SetOutput(os.Stdout)
-
-	// acknowledge fix in go-openapi/spec
-	specPath := filepath.Join("..", "fixtures", "bugs", "1429", "swagger-1429.yaml")
+func TestShared_AppNameOrDefault(t *testing.T) {
+	specPath := filepath.Join("..", "fixtures", "codegen", "shipyard.yml")
 	specDoc, err := loads.Spec(specPath)
-	assert.NoError(t, err)
-
-	opts := testGenOpts()
-	opts.Spec = specPath
-	_, err = validateAndFlattenSpec(&opts, specDoc)
-	assert.NoError(t, err)
-
-	// more aggressive fixture on $refs, with validation errors, but flatten ok
-	specPath = filepath.Join("..", "fixtures", "bugs", "1429", "swagger.yaml")
-	specDoc, err = loads.Spec(specPath)
-	assert.NoError(t, err)
-
-	opts.Spec = specPath
-	opts.FlattenOpts.BasePath = specDoc.SpecFilePath()
-	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
-	opts.FlattenOpts.Minimal = true
-	err = analysis.Flatten(*opts.FlattenOpts)
-	assert.NoError(t, err)
-
-	specDoc, _ = loads.Spec(specPath) // needs reload
-	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
-	opts.FlattenOpts.Minimal = false
-	err = analysis.Flatten(*opts.FlattenOpts)
-	assert.NoError(t, err)
-}
-
-func TestShared_MangleFileName(t *testing.T) {
-	// standard : swag.ToFileName()
-	o := LanguageOpts{}
-	o.Init()
-	res := o.MangleFileName("aFileEndingInOsNameWindows")
-	assert.True(t, strings.HasSuffix(res, "_windows"))
-
-	// golang specific
-	res = golang.MangleFileName("aFileEndingInOsNameWindows")
-	assert.True(t, strings.HasSuffix(res, "_windows_swagger"))
-	res = golang.MangleFileName("aFileEndingInOsNameWindowsAmd64")
-	assert.True(t, strings.HasSuffix(res, "_windows_amd64_swagger"))
-	res = golang.MangleFileName("aFileEndingInTest")
-	assert.True(t, strings.HasSuffix(res, "_test_swagger"))
+	require.NoError(t, err)
+	require.NotNil(t, specDoc.Spec().Info)
+	specDoc.Spec().Info.Title = "    "
+	assert.Equal(t, "Xyz", appNameOrDefault(specDoc, "  ", "xyz"))
 }
 
-func TestShared_ManglePackage(t *testing.T) {
-	o := GoLangOpts()
-	o.Init()
+func TestShared_GatherModel(t *testing.T) {
+	specPath := filepath.Join("..", "fixtures", "codegen", "shipyard.yml")
 
-	for _, v := range []struct {
-		tested       string
-		expectedPath string
-		expectedName string
-	}{
-		{tested: "", expectedPath: "default", expectedName: "default"},
-		{tested: "select", expectedPath: "select_default", expectedName: "select_default"},
-		{tested: "x", expectedPath: "x", expectedName: "x"},
-		{tested: "a/b/c-d/e_f/g", expectedPath: "a/b/c-d/e_f/g", expectedName: "g"},
-		{tested: "a/b/c-d/e_f/g-h", expectedPath: "a/b/c-d/e_f/g_h", expectedName: "g_h"},
-	} {
-		res := o.ManglePackagePath(v.tested, "default")
-		assert.Equal(t, v.expectedPath, res)
-		res = o.ManglePackageName(v.tested, "default")
-		assert.Equal(t, v.expectedName, res)
-	}
-}
-
-func TestShared_Issue1621(t *testing.T) {
-	log.SetOutput(ioutil.Discard)
-	defer log.SetOutput(os.Stdout)
-
-	// acknowledge fix in go-openapi/spec
-	specPath := filepath.Join("..", "fixtures", "bugs", "1621", "fixture-1621.yaml")
 	specDoc, err := loads.Spec(specPath)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
-	opts := testGenOpts()
-	opts.Spec = specPath
-	opts.ValidateSpec = true
-	//t.Logf("path: %s", specDoc.SpecFilePath())
-	_, err = validateAndFlattenSpec(&opts, specDoc)
-	assert.NoError(t, err)
-}
+	_, err = gatherModels(specDoc, []string{"unknown"})
+	assert.Error(t, err)
 
-func TestShared_Issue1614(t *testing.T) {
-	log.SetOutput(ioutil.Discard)
-	defer log.SetOutput(os.Stdout)
+	res, err := gatherModels(specDoc, []string{"Image", "Application"})
+	require.NoError(t, err)
+	assert.Len(t, res, 2)
 
-	// acknowledge fix in go-openapi/spec
-	specPath := filepath.Join("..", "fixtures", "bugs", "1614", "gitea.json")
-	specDoc, err := loads.Spec(specPath)
-	assert.NoError(t, err)
+	res, err = gatherModels(specDoc, []string{"Image", "Application"})
+	require.NoError(t, err)
+	assert.Len(t, res, 2)
 
-	opts := testGenOpts()
-	opts.Spec = specPath
-	opts.ValidateSpec = true
-	t.Logf("path: %s", specDoc.SpecFilePath())
-	_, err = validateAndFlattenSpec(&opts, specDoc)
-	assert.NoError(t, err)
+	res, err = gatherModels(specDoc, []string{})
+	require.NoError(t, err)
+	assert.Len(t, res, 4)
 }
 
-func TestPascalize(t *testing.T) {
-	assert.Equal(t, "Plus1", pascalize("+1"))
-	assert.Equal(t, "Plus", pascalize("+"))
-	assert.Equal(t, "Minus1", pascalize("-1"))
-	assert.Equal(t, "Minus", pascalize("-"))
-	assert.Equal(t, "Nr8", pascalize("8"))
-
-	assert.Equal(t, "Hello", pascalize("+hello"))
-
-	// other values from swag rules
-	assert.Equal(t, "At8", pascalize("@8"))
-	assert.Equal(t, "AtHello", pascalize("@hello"))
-	assert.Equal(t, "Bang8", pascalize("!8"))
-	assert.Equal(t, "At", pascalize("@"))
-
-	// # values
-	assert.Equal(t, "Hello", pascalize("#hello"))
-	assert.Equal(t, "BangHello", pascalize("#!hello"))
-	assert.Equal(t, "HashTag8", pascalize("#8"))
-	assert.Equal(t, "HashTag", pascalize("#"))
-
-	// single '_'
-	assert.Equal(t, "Nr", pascalize("_"))
-	assert.Equal(t, "Hello", pascalize("_hello"))
+func TestShared_DumpWrongData(t *testing.T) {
+	assert.Error(t, dumpData(struct {
+		A func() string
+		B string
+	}{
+		A: func() string { return "" },
+		B: "xyz",
+	}))
 
-	// remove spaces
-	assert.Equal(t, "HelloWorld", pascalize("# hello world"))
-	assert.Equal(t, "HashTag8HelloWorld", pascalize("# 8 hello world"))
+	assert.NoError(t, dumpData(struct {
+		A func() string `json:"-"`
+		B string
+	}{
+		A: func() string { return "" },
+		B: "xyz",
+	}))
 
-	assert.Equal(t, "Empty", pascalize(""))
+	assert.NoError(t, dumpData(struct {
+		a func() string
+		B string
+	}{
+		a: func() string { return "" },
+		B: "xyz",
+	}))
 }
diff --git a/generator/spec_test.go b/generator/spec_test.go
new file mode 100644
index 00000000..02cccc4d
--- /dev/null
+++ b/generator/spec_test.go
@@ -0,0 +1,87 @@
+package generator
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/go-openapi/analysis"
+	"github.com/go-openapi/loads"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestSpec_Issue1429(t *testing.T) {
+	log.SetOutput(ioutil.Discard)
+	defer log.SetOutput(os.Stdout)
+
+	// acknowledge fix in go-openapi/spec
+	specPath := filepath.Join("..", "fixtures", "bugs", "1429", "swagger-1429.yaml")
+	_, err := loads.Spec(specPath)
+	assert.NoError(t, err)
+
+	opts := testGenOpts()
+	opts.Spec = specPath
+	_, err = opts.validateAndFlattenSpec()
+	assert.NoError(t, err)
+
+	// more aggressive fixture on $refs, with validation errors, but flatten ok
+	specPath = filepath.Join("..", "fixtures", "bugs", "1429", "swagger.yaml")
+	specDoc, err := loads.Spec(specPath)
+	assert.NoError(t, err)
+
+	opts.Spec = specPath
+	opts.FlattenOpts.BasePath = specDoc.SpecFilePath()
+	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
+	opts.FlattenOpts.Minimal = true
+	err = analysis.Flatten(*opts.FlattenOpts)
+	assert.NoError(t, err)
+
+	specDoc, _ = loads.Spec(specPath) // needs reload
+	opts.FlattenOpts.Spec = analysis.New(specDoc.Spec())
+	opts.FlattenOpts.Minimal = false
+	err = analysis.Flatten(*opts.FlattenOpts)
+	assert.NoError(t, err)
+}
+
+func TestSpec_FindSwaggerSpec(t *testing.T) {
+	keepErr := func(_ string, err error) error { return err }
+	assert.Error(t, keepErr(findSwaggerSpec("")))
+	assert.Error(t, keepErr(findSwaggerSpec("nowhere")))
+	assert.Error(t, keepErr(findSwaggerSpec(filepath.Join("..", "fixtures"))))
+	assert.NoError(t, keepErr(findSwaggerSpec(filepath.Join("..", "fixtures", "codegen", "shipyard.yml"))))
+}
+
+func TestSpec_Issue1621(t *testing.T) {
+	log.SetOutput(ioutil.Discard)
+	defer log.SetOutput(os.Stdout)
+
+	// acknowledge fix in go-openapi/spec
+	specPath := filepath.Join("..", "fixtures", "bugs", "1621", "fixture-1621.yaml")
+	_, err := loads.Spec(specPath)
+	require.NoError(t, err)
+
+	opts := testGenOpts()
+	opts.Spec = specPath
+	opts.ValidateSpec = true
+	_, err = opts.validateAndFlattenSpec()
+	assert.NoError(t, err)
+}
+
+func TestShared_Issue1614(t *testing.T) {
+	log.SetOutput(ioutil.Discard)
+	defer log.SetOutput(os.Stdout)
+
+	// acknowledge fix in go-openapi/spec
+	specPath := filepath.Join("..", "fixtures", "bugs", "1614", "gitea.json")
+	_, err := loads.Spec(specPath)
+	require.NoError(t, err)
+
+	opts := testGenOpts()
+	opts.Spec = specPath
+	opts.ValidateSpec = true
+	_, err = opts.validateAndFlattenSpec()
+	assert.NoError(t, err)
+}
diff --git a/generator/support_test.go b/generator/support_test.go
index 4960669b..76fda616 100644
--- a/generator/support_test.go
+++ b/generator/support_test.go
@@ -4,7 +4,6 @@ import (
 	"os"
 	"path/filepath"
 	goruntime "runtime"
-	"strings"
 	"testing"
 )
 
@@ -52,7 +51,7 @@ func TestCheckPrefixFetchRelPath(t *testing.T) {
 		actualok, actualpath := checkPrefixAndFetchRelativePath(item.childpath, item.parentpath)
 
 		if goruntime.GOOS == "windows" {
-			item.path = strings.Replace(item.path, "/", "\\", -1)
+			item.path = filepath.FromSlash(item.path)
 		}
 
 		switch {
@@ -77,6 +76,7 @@ func TestBaseImport(t *testing.T) {
 	// 3. Check results.
 
 	oldgopath := os.Getenv("GOPATH")
+	golang := GoLangOpts()
 	defer func() {
 		_ = os.Setenv("GOPATH", oldgopath)
 		_ = os.RemoveAll(filepath.Join(tempdir, "root"))
@@ -96,13 +96,9 @@ func TestBaseImport(t *testing.T) {
 			// Create Symlink
 			if err := os.Symlink(item.symlinkdest, item.symlinksrc); err == nil {
 
-				// Test
+				// Test (baseImport always with /)
 				actualpath := golang.baseImport(item.targetpath)
 
-				if goruntime.GOOS == "windows" {
-					item.expectedpath = strings.Replace(item.expectedpath, "/", "\\", -1)
-				}
-
 				if actualpath != item.expectedpath {
 					t.Errorf("baseImport(%s): expected %s, actual %s", item.targetpath, item.expectedpath, actualpath)
 				}
diff --git a/generator/template_repo_test.go b/generator/template_repo_test.go
index 1f7a8c68..0aef4789 100644
--- a/generator/template_repo_test.go
+++ b/generator/template_repo_test.go
@@ -9,9 +9,11 @@ import (
 
 	"github.com/go-openapi/loads"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
-var (
+const (
+	// Test template environment
 	singleTemplate        = `test`
 	multipleDefinitions   = `{{ define "T1" }}T1{{end}}{{ define "T2" }}T2{{end}}`
 	dependantTemplate     = `{{ template "T1" }}D1`
@@ -21,10 +23,10 @@ var (
 	customMultiple        = `{{define "bindprimitiveparam" }}custom primitive{{end}}`
 	customNewTemplate     = `new template`
 	customExistingUsesNew = `{{define "bindprimitiveparam" }}{{ template "newtemplate" }}{{end}}`
-	// Test template environment
-	copyright        = `{{ .Copyright }}`
-	targetImportPath = `{{ .TargetImportPath }}`
-	funcTpl          = `
+)
+
+func testFuncTpl() string {
+	return `
 Pascalize={{ pascalize "WeArePonies_Of_the_round table" }}
 Snakize={{ snakize "WeArePonies_Of_the_round table" }}
 Humanize={{ humanize "WeArePonies_Of_the_round table" }}
@@ -57,31 +59,29 @@ PascalizeSpecialChar3={{ pascalize "1" }}
 PascalizeSpecialChar4={{ pascalize "-" }}
 PascalizeSpecialChar5={{ pascalize "+" }}
 `
-)
+}
 
 func TestTemplates_CustomTemplates(t *testing.T) {
 
 	var buf bytes.Buffer
 	headerTempl, err := templates.Get("bindprimitiveparam")
-
-	assert.Nil(t, err)
+	assert.NoError(t, err)
 
 	err = headerTempl.Execute(&buf, nil)
-
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, buf)
 	assert.Equal(t, "\n", buf.String())
 
 	buf.Reset()
 	err = templates.AddFile("bindprimitiveparam", customHeader)
+	assert.NoError(t, err)
 
-	assert.Nil(t, err)
 	headerTempl, err = templates.Get("bindprimitiveparam")
-
-	assert.Nil(t, err)
+	assert.NoError(t, err)
+	assert.NotNil(t, headerTempl)
 
 	err = headerTempl.Execute(&buf, nil)
-
-	assert.Nil(t, err)
+	assert.NoError(t, err)
 	assert.Equal(t, "custom header", buf.String())
 
 }
@@ -90,15 +90,14 @@ func TestTemplates_CustomTemplatesMultiple(t *testing.T) {
 	var buf bytes.Buffer
 
 	err := templates.AddFile("differentFileName", customMultiple)
+	assert.NoError(t, err)
 
-	assert.Nil(t, err)
 	headerTempl, err := templates.Get("bindprimitiveparam")
-
-	assert.Nil(t, err)
+	assert.NoError(t, err)
 
 	err = headerTempl.Execute(&buf, nil)
+	require.NoError(t, err)
 
-	assert.Nil(t, err)
 	assert.Equal(t, "custom primitive", buf.String())
 }
 
@@ -106,16 +105,16 @@ func TestTemplates_CustomNewTemplates(t *testing.T) {
 	var buf bytes.Buffer
 
 	err := templates.AddFile("newtemplate", customNewTemplate)
-	assert.Nil(t, err)
+	assert.NoError(t, err)
 
 	err = templates.AddFile("existingUsesNew", customExistingUsesNew)
-	assert.Nil(t, err)
+	assert.NoError(t, err)
 
 	headerTempl, err := templates.Get("bindprimitiveparam")
-	assert.Nil(t, err)
+	assert.NoError(t, err)
 
 	err = headerTempl.Execute(&buf, nil)
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, "new template", buf.String())
 }
@@ -128,14 +127,11 @@ func TestTemplates_RepoLoadingTemplates(t *testing.T) {
 	assert.NoError(t, err)
 
 	templ, err := repo.Get("simple")
-
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	var b bytes.Buffer
-
 	err = templ.Execute(&b, nil)
-
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, "test", b.String())
 }
@@ -149,16 +145,19 @@ func TestTemplates_RepoLoadsAllTemplatesDefined(t *testing.T) {
 	assert.NoError(t, err)
 
 	templ, err := repo.Get("multiple")
-	assert.Nil(t, err)
+	assert.NoError(t, err)
+
 	err = templ.Execute(&b, nil)
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, "", b.String())
 
 	templ, err = repo.Get("T1")
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, templ)
+
 	err = templ.Execute(&b, nil)
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, "T1", b.String())
 }
@@ -176,18 +175,18 @@ func TestTemplates_RepoLoadsAllDependantTemplates(t *testing.T) {
 
 	err := repo.AddFile("multiple", multipleDefinitions)
 	assert.NoError(t, err)
+
 	err = repo.AddFile("dependant", dependantTemplate)
 	assert.NoError(t, err)
 
 	templ, err := repo.Get("dependant")
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, templ)
 
 	err = templ.Execute(&b, nil)
-
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, "T1D1", b.String())
-
 }
 
 func TestTemplates_RepoRecursiveTemplates(t *testing.T) {
@@ -197,11 +196,14 @@ func TestTemplates_RepoRecursiveTemplates(t *testing.T) {
 
 	err := repo.AddFile("c1", cirularDeps1)
 	assert.NoError(t, err)
+
 	err = repo.AddFile("c2", cirularDeps2)
 	assert.NoError(t, err)
 
 	templ, err := repo.Get("c1")
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, templ)
+
 	data := testData{
 		Name: "Root",
 		Children: []testData{
@@ -210,9 +212,7 @@ func TestTemplates_RepoRecursiveTemplates(t *testing.T) {
 	}
 	expected := `Root: Children`
 	err = templ.Execute(&b, data)
-
-	assert.Nil(t, err)
-
+	require.NoError(t, err)
 	assert.Equal(t, expected, b.String())
 
 	data = testData{
@@ -227,8 +227,7 @@ func TestTemplates_RepoRecursiveTemplates(t *testing.T) {
 	expected = `Root: Child1: Children`
 
 	err = templ.Execute(&b, data)
-
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, expected, b.String())
 
@@ -244,8 +243,7 @@ func TestTemplates_RepoRecursiveTemplates(t *testing.T) {
 	expected = `Root: Children`
 
 	err = templ.Execute(&b, data)
-
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, expected, b.String())
 }
@@ -255,6 +253,7 @@ func TestTemplates_RepoRecursiveTemplates(t *testing.T) {
 
 // Test copyright definition
 func TestTemplates_DefinitionCopyright(t *testing.T) {
+	const copyright = `{{ .Copyright }}`
 	log.SetOutput(os.Stdout)
 
 	repo := NewRepository(nil)
@@ -263,7 +262,8 @@ func TestTemplates_DefinitionCopyright(t *testing.T) {
 	assert.NoError(t, err)
 
 	templ, err := repo.Get("copyright")
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, templ)
 
 	opts := opts()
 	opts.Copyright = "My copyright clause"
@@ -271,22 +271,23 @@ func TestTemplates_DefinitionCopyright(t *testing.T) {
 
 	// executes template against model definitions
 	genModel, err := getModelEnvironment("../fixtures/codegen/todolist.models.yml", opts)
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, genModel)
 
 	rendered := bytes.NewBuffer(nil)
 	err = templ.Execute(rendered, genModel)
-	assert.Nil(t, err)
-
+	assert.NoError(t, err)
 	assert.Equal(t, expected, rendered.String())
 
 	// executes template against operations definitions
 	genOperation, err := getOperationEnvironment("get", "/media/search", "../fixtures/codegen/instagram.yml", opts)
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, genOperation)
 
 	rendered.Reset()
 
 	err = templ.Execute(rendered, genOperation)
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, expected, rendered.String())
 
@@ -294,6 +295,7 @@ func TestTemplates_DefinitionCopyright(t *testing.T) {
 
 // Test TargetImportPath definition
 func TestTemplates_DefinitionTargetImportPath(t *testing.T) {
+	const targetImportPath = `{{ .TargetImportPath }}`
 	log.SetOutput(os.Stdout)
 
 	repo := NewRepository(nil)
@@ -302,7 +304,8 @@ func TestTemplates_DefinitionTargetImportPath(t *testing.T) {
 	assert.NoError(t, err)
 
 	templ, err := repo.Get("targetimportpath")
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, templ)
 
 	opts := opts()
 	// Non existing target would panic: to be tested too, but in another module
@@ -311,22 +314,24 @@ func TestTemplates_DefinitionTargetImportPath(t *testing.T) {
 
 	// executes template against model definitions
 	genModel, err := getModelEnvironment("../fixtures/codegen/todolist.models.yml", opts)
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, genModel)
 
 	rendered := bytes.NewBuffer(nil)
 	err = templ.Execute(rendered, genModel)
-	assert.Nil(t, err)
+	assert.NoError(t, err)
 
 	assert.Equal(t, expected, rendered.String())
 
 	// executes template against operations definitions
 	genOperation, err := getOperationEnvironment("get", "/media/search", "../fixtures/codegen/instagram.yml", opts)
-	assert.Nil(t, err)
+	require.NoError(t, err)
+	require.NotNil(t, genOperation)
 
 	rendered.Reset()
 
 	err = templ.Execute(rendered, genOperation)
-	assert.Nil(t, err)
+	require.NoError(t, err)
 
 	assert.Equal(t, expected, rendered.String())
 
@@ -381,54 +386,55 @@ func getOperationEnvironment(operation string, path string, spec string, opts *G
 // blocking anyone for now.
 func TestTemplates_FuncMap(t *testing.T) {
 	log.SetOutput(os.Stdout)
+	funcTpl := testFuncTpl()
 
 	err := templates.AddFile("functpl", funcTpl)
-	if assert.NoError(t, err) {
-		templ, err := templates.Get("functpl")
-		if assert.Nil(t, err) {
-			opts := opts()
-			// executes template against model definitions
-			genModel, err := getModelEnvironment("../fixtures/codegen/todolist.models.yml", opts)
-			if assert.Nil(t, err) {
-				rendered := bytes.NewBuffer(nil)
-				err = templ.Execute(rendered, genModel)
-				if assert.Nil(t, err) {
-					assert.Contains(t, rendered.String(), "Pascalize=WeArePoniesOfTheRoundTable\n")
-					assert.Contains(t, rendered.String(), "Snakize=we_are_ponies_of_the_round_table\n")
-					assert.Contains(t, rendered.String(), "Humanize=we are ponies of the round table\n")
-					assert.Contains(t, rendered.String(), "PluralizeFirstWord=ponies of the round table\n")
-					assert.Contains(t, rendered.String(), "PluralizeFirstOfOneWord=dwarves\n")
-					assert.Contains(t, rendered.String(), "PluralizeFirstOfNoWord=\n")
-					assert.Contains(t, rendered.String(), "StripPackage=suffix\n")
-					assert.Contains(t, rendered.String(), "StripNoPackage=suffix\n")
-					assert.Contains(t, rendered.String(), "StripEmptyPackage=\n")
-					assert.Contains(t, rendered.String(), "DropPackage=suffix\n")
-					assert.Contains(t, rendered.String(), "DropNoPackage=suffix\n")
-					assert.Contains(t, rendered.String(), "DropEmptyPackage=\n")
-					assert.Contains(t, rendered.String(), "DropEmptyPackage=\n")
-					assert.Contains(t, rendered.String(), "ImportRuntime=true\n")
-					assert.Contains(t, rendered.String(), "DoNotImport=false\n")
-					assert.Contains(t, rendered.String(), "PadSurround1=-,-,-,padme,-,-,-,-,-,-,-,-\n")
-					assert.Contains(t, rendered.String(), "PadSurround2=padme,-,-,-,-,-,-,-,-,-,-,-\n")
-					assert.Contains(t, rendered.String(), "Json=[\"github.com/go-openapi/errors\",\"github.com/go-openapi/runtime\",\"github.com/go-openapi/swag\",\"github.com/go-openapi/validate\"]")
-					assert.Contains(t, rendered.String(), "\"TargetImportPath\": \"github.com/go-swagger/go-swagger/generator\"")
-					assert.Contains(t, rendered.String(), "Snakize1=ending_in_os_name_linux_swagger\n")
-					assert.Contains(t, rendered.String(), "Snakize2=ending_in_arch_name_linux_amd64_swagger\n")
-					assert.Contains(t, rendered.String(), "Snakize3=ending_in_test_swagger\n")
-					assert.Contains(t, rendered.String(), "toPackage1=a/b-c/d_e\n")
-					assert.Contains(t, rendered.String(), "toPackage2=a.a/b_c/d_e\n")
-					assert.Contains(t, rendered.String(), "toPackage3=d_e\n")
-					assert.Contains(t, rendered.String(), "toPackage4=d_e\n")
-					assert.Contains(t, rendered.String(), "toPackageName=f_g\n")
-					assert.Contains(t, rendered.String(), "PascalizeSpecialChar1=Plus1\n")
-					assert.Contains(t, rendered.String(), "PascalizeSpecialChar2=Minus1\n")
-					assert.Contains(t, rendered.String(), "PascalizeSpecialChar3=Nr1\n")
-					assert.Contains(t, rendered.String(), "PascalizeSpecialChar4=Minus\n")
-					assert.Contains(t, rendered.String(), "PascalizeSpecialChar5=Plus\n")
-				}
-			}
-		}
-	}
+	require.NoError(t, err)
+
+	templ, err := templates.Get("functpl")
+	require.NoError(t, err)
+
+	opts := opts()
+	// executes template against model definitions
+	genModel, err := getModelEnvironment("../fixtures/codegen/todolist.models.yml", opts)
+	require.NoError(t, err)
+
+	rendered := bytes.NewBuffer(nil)
+	err = templ.Execute(rendered, genModel)
+	require.NoError(t, err)
+
+	assert.Contains(t, rendered.String(), "Pascalize=WeArePoniesOfTheRoundTable\n")
+	assert.Contains(t, rendered.String(), "Snakize=we_are_ponies_of_the_round_table\n")
+	assert.Contains(t, rendered.String(), "Humanize=we are ponies of the round table\n")
+	assert.Contains(t, rendered.String(), "PluralizeFirstWord=ponies of the round table\n")
+	assert.Contains(t, rendered.String(), "PluralizeFirstOfOneWord=dwarves\n")
+	assert.Contains(t, rendered.String(), "PluralizeFirstOfNoWord=\n")
+	assert.Contains(t, rendered.String(), "StripPackage=suffix\n")
+	assert.Contains(t, rendered.String(), "StripNoPackage=suffix\n")
+	assert.Contains(t, rendered.String(), "StripEmptyPackage=\n")
+	assert.Contains(t, rendered.String(), "DropPackage=suffix\n")
+	assert.Contains(t, rendered.String(), "DropNoPackage=suffix\n")
+	assert.Contains(t, rendered.String(), "DropEmptyPackage=\n")
+	assert.Contains(t, rendered.String(), "DropEmptyPackage=\n")
+	assert.Contains(t, rendered.String(), "ImportRuntime=true\n")
+	assert.Contains(t, rendered.String(), "DoNotImport=false\n")
+	assert.Contains(t, rendered.String(), "PadSurround1=-,-,-,padme,-,-,-,-,-,-,-,-\n")
+	assert.Contains(t, rendered.String(), "PadSurround2=padme,-,-,-,-,-,-,-,-,-,-,-\n")
+	assert.Contains(t, rendered.String(), "Json=[\"github.com/go-openapi/errors\",\"github.com/go-openapi/runtime\",\"github.com/go-openapi/swag\",\"github.com/go-openapi/validate\"]")
+	assert.Contains(t, rendered.String(), "\"TargetImportPath\": \"github.com/go-swagger/go-swagger/generator\"")
+	assert.Contains(t, rendered.String(), "Snakize1=ending_in_os_name_linux_swagger\n")
+	assert.Contains(t, rendered.String(), "Snakize2=ending_in_arch_name_linux_amd64_swagger\n")
+	assert.Contains(t, rendered.String(), "Snakize3=ending_in_test_swagger\n")
+	assert.Contains(t, rendered.String(), "toPackage1=a/b-c/d_e\n")
+	assert.Contains(t, rendered.String(), "toPackage2=a.a/b_c/d_e\n")
+	assert.Contains(t, rendered.String(), "toPackage3=d_e\n")
+	assert.Contains(t, rendered.String(), "toPackage4=d_e\n")
+	assert.Contains(t, rendered.String(), "toPackageName=f_g\n")
+	assert.Contains(t, rendered.String(), "PascalizeSpecialChar1=Plus1\n")
+	assert.Contains(t, rendered.String(), "PascalizeSpecialChar2=Minus1\n")
+	assert.Contains(t, rendered.String(), "PascalizeSpecialChar3=Nr1\n")
+	assert.Contains(t, rendered.String(), "PascalizeSpecialChar4=Minus\n")
+	assert.Contains(t, rendered.String(), "PascalizeSpecialChar5=Plus\n")
 }
 
 // AddFile() global package function (protected vs unprotected)
@@ -436,16 +442,18 @@ func TestTemplates_FuncMap(t *testing.T) {
 // is generally preferred.
 func TestTemplates_AddFile(t *testing.T) {
 	log.SetOutput(os.Stdout)
+	funcTpl := testFuncTpl()
 
 	// unprotected
 	err := AddFile("functpl", funcTpl)
-	if assert.NoError(t, err) {
-		_, erg := templates.Get("functpl")
-		assert.Nil(t, erg)
-	}
+	require.NoError(t, err)
+
+	_, err = templates.Get("functpl")
+	require.NoError(t, err)
+
 	// protected
 	err = AddFile("schemabody", funcTpl)
-	assert.Error(t, err)
+	require.Error(t, err)
 	assert.Contains(t, err.Error(), "cannot overwrite protected template")
 }
 
@@ -455,12 +463,12 @@ func TestTemplates_LoadDir(t *testing.T) {
 
 	// Fails
 	err := templates.LoadDir("")
-	assert.Error(t, err)
+	require.Error(t, err)
 	assert.Contains(t, err.Error(), "could not complete")
 
 	// Fails again (from any dir?)
 	err = templates.LoadDir("templates")
-	assert.Error(t, err)
+	require.Error(t, err)
 	assert.Contains(t, err.Error(), "cannot overwrite protected template")
 
 	// TODO: success case
@@ -474,7 +482,7 @@ func TestTemplates_LoadDir(t *testing.T) {
 	}()
 
 	protectedTemplates = make(map[string]bool)
-	repo := NewRepository(FuncMap)
+	repo := NewRepository(FuncMapFunc(DefaultLanguageFunc()))
 	err = repo.LoadDir("templates")
 	assert.NoError(t, err)
 }
@@ -486,6 +494,7 @@ func TestTemplates_SetAllowOverride(t *testing.T) {
 	// adding protected file with allowOverride set to false fails
 	templates.SetAllowOverride(false)
 	err := templates.AddFile("schemabody", "some data")
+	require.Error(t, err)
 	assert.Contains(t, err.Error(), "cannot overwrite protected template schemabody")
 
 	// adding protected file with allowOverride set to true should not fail
@@ -502,7 +511,7 @@ func TestTemplates_LoadContrib(t *testing.T) {
 		wantError bool
 	}{
 		{
-			name:      "None_existing_contributor_tempalte",
+			name:      "None_existing_contributor_template",
 			template:  "NonExistingContributorTemplate",
 			wantError: true,
 		},
@@ -540,23 +549,62 @@ func TestTemplates_DumpTemplates(t *testing.T) {
 	assert.Contains(t, buf.String(), "## tupleSerializer")
 	assert.Contains(t, buf.String(), "Defined in `tupleserializer.gotmpl`")
 	assert.Contains(t, buf.String(), "####requires \n - schemaType")
-	//fmt.Println(buf)
 }
 
-// Go literal initializer func
-func TestTemplates_GoSliceInitializer(t *testing.T) {
-	a0 := []interface{}{"a", "b"}
-	res, err := goSliceInitializer(a0)
-	assert.NoError(t, err)
-	assert.Equal(t, `{"a","b",}`, res)
+func TestFuncMap_Pascalize(t *testing.T) {
+	assert.Equal(t, "Plus1", pascalize("+1"))
+	assert.Equal(t, "Plus", pascalize("+"))
+	assert.Equal(t, "Minus1", pascalize("-1"))
+	assert.Equal(t, "Minus", pascalize("-"))
+	assert.Equal(t, "Nr8", pascalize("8"))
 
-	a1 := []interface{}{[]interface{}{"a", "b"}, []interface{}{"c", "d"}}
-	res, err = goSliceInitializer(a1)
-	assert.NoError(t, err)
-	assert.Equal(t, `{{"a","b",},{"c","d",},}`, res)
+	assert.Equal(t, "Hello", pascalize("+hello"))
 
-	a2 := map[string]interface{}{"a": "y", "b": "z"}
-	res, err = goSliceInitializer(a2)
-	assert.NoError(t, err)
-	assert.Equal(t, `{"a":"y","b":"z",}`, res)
+	// other values from swag rules
+	assert.Equal(t, "At8", pascalize("@8"))
+	assert.Equal(t, "AtHello", pascalize("@hello"))
+	assert.Equal(t, "Bang8", pascalize("!8"))
+	assert.Equal(t, "At", pascalize("@"))
+
+	// # values
+	assert.Equal(t, "Hello", pascalize("#hello"))
+	assert.Equal(t, "BangHello", pascalize("#!hello"))
+	assert.Equal(t, "HashTag8", pascalize("#8"))
+	assert.Equal(t, "HashTag", pascalize("#"))
+
+	// single '_'
+	assert.Equal(t, "Nr", pascalize("_"))
+	assert.Equal(t, "Hello", pascalize("_hello"))
+
+	// remove spaces
+	assert.Equal(t, "HelloWorld", pascalize("# hello world"))
+	assert.Equal(t, "HashTag8HelloWorld", pascalize("# 8 hello world"))
+
+	assert.Equal(t, "Empty", pascalize(""))
+}
+
+func TestFuncMap_DropPackage(t *testing.T) {
+	assert.Equal(t, "trail", dropPackage("base.trail"))
+	assert.Equal(t, "trail", dropPackage("base.another.trail"))
+	assert.Equal(t, "trail", dropPackage("trail"))
+}
+
+func TestFuncMap_AsJSON(t *testing.T) {
+	for _, jsonFunc := range []func(interface{}) (string, error){
+		asJSON,
+		asPrettyJSON,
+	} {
+		res, err := jsonFunc(struct {
+			A string `json:"a"`
+			B int
+		}{A: "good", B: 3})
+		require.NoError(t, err)
+		assert.JSONEq(t, `{"a":"good","B":3}`, res)
+
+		_, err = jsonFunc(struct {
+			A string `json:"a"`
+			B func() string
+		}{A: "good", B: func() string { return "" }})
+		require.Error(t, err)
+	}
 }