github.com/go-swagger/go-swagger@v0.31.0/generator/template_repo_test.go (about)

     1  package generator
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/go-openapi/loads"
     8  	"github.com/go-openapi/swag"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  const (
    14  	// Test template environment
    15  	singleTemplate        = `test`
    16  	multipleDefinitions   = `{{ define "T1" }}T1{{end}}{{ define "T2" }}T2{{end}}`
    17  	dependantTemplate     = `{{ template "T1" }}D1`
    18  	cirularDeps1          = `{{ define "T1" }}{{ .Name }}: {{ range .Children }}{{ template "T2" . }}{{end}}{{end}}{{template "T1" . }}`
    19  	cirularDeps2          = `{{ define "T2" }}{{if .Recurse }}{{ template "T1" . }}{{ else }}Children{{end}}{{end}}`
    20  	customHeader          = `custom header`
    21  	customMultiple        = `{{define "bindprimitiveparam" }}custom primitive{{end}}`
    22  	customNewTemplate     = `new template`
    23  	customExistingUsesNew = `{{define "bindprimitiveparam" }}{{ template "newtemplate" }}{{end}}`
    24  )
    25  
    26  func testFuncTpl() string {
    27  	return `
    28  Pascalize={{ pascalize "WeArePonies_Of_the_round table" }}
    29  Snakize={{ snakize "WeArePonies_Of_the_round table" }}
    30  Humanize={{ humanize "WeArePonies_Of_the_round table" }}
    31  PluralizeFirstWord={{ pluralizeFirstWord "pony of the round table" }}
    32  PluralizeFirstOfOneWord={{ pluralizeFirstWord "dwarf" }}
    33  PluralizeFirstOfNoWord={{ pluralizeFirstWord "" }}
    34  DropPackage={{ dropPackage "prefix.suffix" }}
    35  DropNoPackage={{ dropPackage "suffix" }}
    36  DropEmptyPackage={{ dropPackage "" }}
    37  ContainsString={{ contains .DependsOn "x"}}
    38  DoesNotContainString={{ contains .DependsOn "y"}}
    39  PadSurround1={{ padSurround "padme" "-" 3 12}}
    40  PadSurround2={{ padSurround "padme" "-" 0 12}}
    41  Json={{ json .DefaultImports }}
    42  PrettyJson={{ prettyjson . }}
    43  Snakize1={{ snakize "endingInOsNameLinux" }}
    44  Snakize2={{ snakize "endingInArchNameLinuxAmd64" }}
    45  Snakize3={{ snakize "endingInTest" }}
    46  toPackage1={{ toPackage "a/b-c/d-e" }}
    47  toPackage2={{ toPackage "a.a/b_c/d_e" }}
    48  toPackage3={{ toPackage "d_e" }}
    49  toPackage4={{ toPackage "d-e" }}
    50  toPackageName={{ toPackageName "d-e/f-g" }}
    51  PascalizeSpecialChar1={{ pascalize "+1" }}
    52  PascalizeSpecialChar2={{ pascalize "-1" }}
    53  PascalizeSpecialChar3={{ pascalize "1" }}
    54  PascalizeSpecialChar4={{ pascalize "-" }}
    55  PascalizeSpecialChar5={{ pascalize "+" }}
    56  PascalizeCleanupEnumVariant1={{ pascalize (cleanupEnumVariant "2.4Ghz") }}
    57  Dict={{ template "dictTemplate" dict "Animal" "Pony" "Shape" "round" "Furniture" "table" }}
    58  {{ define "dictTemplate" }}{{ .Animal }} of the {{ .Shape }} {{ .Furniture }}{{ end }}
    59  `
    60  }
    61  
    62  func TestTemplates_CustomTemplates(t *testing.T) {
    63  	var buf bytes.Buffer
    64  	headerTempl, err := templates.Get("bindprimitiveparam")
    65  	require.NoError(t, err)
    66  
    67  	err = headerTempl.Execute(&buf, nil)
    68  	require.NoError(t, err)
    69  	require.NotNil(t, buf)
    70  	assert.Equal(t, "\n", buf.String())
    71  
    72  	buf.Reset()
    73  	err = templates.AddFile("bindprimitiveparam", customHeader)
    74  	require.NoError(t, err)
    75  
    76  	headerTempl, err = templates.Get("bindprimitiveparam")
    77  	require.NoError(t, err)
    78  	assert.NotNil(t, headerTempl)
    79  
    80  	err = headerTempl.Execute(&buf, nil)
    81  	require.NoError(t, err)
    82  	assert.Equal(t, "custom header", buf.String())
    83  }
    84  
    85  func TestTemplates_CustomTemplatesMultiple(t *testing.T) {
    86  	var buf bytes.Buffer
    87  
    88  	err := templates.AddFile("differentFileName", customMultiple)
    89  	require.NoError(t, err)
    90  
    91  	headerTempl, err := templates.Get("bindprimitiveparam")
    92  	require.NoError(t, err)
    93  
    94  	err = headerTempl.Execute(&buf, nil)
    95  	require.NoError(t, err)
    96  
    97  	assert.Equal(t, "custom primitive", buf.String())
    98  }
    99  
   100  func TestTemplates_CustomNewTemplates(t *testing.T) {
   101  	var buf bytes.Buffer
   102  
   103  	err := templates.AddFile("newtemplate", customNewTemplate)
   104  	require.NoError(t, err)
   105  
   106  	err = templates.AddFile("existingUsesNew", customExistingUsesNew)
   107  	require.NoError(t, err)
   108  
   109  	headerTempl, err := templates.Get("bindprimitiveparam")
   110  	require.NoError(t, err)
   111  
   112  	err = headerTempl.Execute(&buf, nil)
   113  	require.NoError(t, err)
   114  
   115  	assert.Equal(t, "new template", buf.String())
   116  }
   117  
   118  func TestTemplates_RepoLoadingTemplates(t *testing.T) {
   119  	repo := NewRepository(nil)
   120  
   121  	err := repo.AddFile("simple", singleTemplate)
   122  	require.NoError(t, err)
   123  
   124  	templ, err := repo.Get("simple")
   125  	require.NoError(t, err)
   126  
   127  	var b bytes.Buffer
   128  	err = templ.Execute(&b, nil)
   129  	require.NoError(t, err)
   130  
   131  	assert.Equal(t, "test", b.String())
   132  }
   133  
   134  func TestTemplates_RepoLoadsAllTemplatesDefined(t *testing.T) {
   135  	var b bytes.Buffer
   136  	repo := NewRepository(nil)
   137  
   138  	err := repo.AddFile("multiple", multipleDefinitions)
   139  	require.NoError(t, err)
   140  
   141  	templ, err := repo.Get("multiple")
   142  	require.NoError(t, err)
   143  
   144  	err = templ.Execute(&b, nil)
   145  	require.NoError(t, err)
   146  
   147  	assert.Equal(t, "", b.String())
   148  
   149  	templ, err = repo.Get("T1")
   150  	require.NoError(t, err)
   151  	require.NotNil(t, templ)
   152  
   153  	err = templ.Execute(&b, nil)
   154  	require.NoError(t, err)
   155  
   156  	assert.Equal(t, "T1", b.String())
   157  }
   158  
   159  type testData struct {
   160  	Children []testData
   161  	Name     string
   162  	Recurse  bool
   163  }
   164  
   165  func TestTemplates_RepoLoadsAllDependantTemplates(t *testing.T) {
   166  	var b bytes.Buffer
   167  	repo := NewRepository(nil)
   168  
   169  	err := repo.AddFile("multiple", multipleDefinitions)
   170  	require.NoError(t, err)
   171  
   172  	err = repo.AddFile("dependant", dependantTemplate)
   173  	require.NoError(t, err)
   174  
   175  	templ, err := repo.Get("dependant")
   176  	require.NoError(t, err)
   177  	require.NotNil(t, templ)
   178  
   179  	err = templ.Execute(&b, nil)
   180  	require.NoError(t, err)
   181  
   182  	assert.Equal(t, "T1D1", b.String())
   183  }
   184  
   185  func TestTemplates_RepoRecursiveTemplates(t *testing.T) {
   186  	var b bytes.Buffer
   187  	repo := NewRepository(nil)
   188  
   189  	err := repo.AddFile("c1", cirularDeps1)
   190  	require.NoError(t, err)
   191  
   192  	err = repo.AddFile("c2", cirularDeps2)
   193  	require.NoError(t, err)
   194  
   195  	templ, err := repo.Get("c1")
   196  	require.NoError(t, err)
   197  	require.NotNil(t, templ)
   198  
   199  	data := testData{
   200  		Name: "Root",
   201  		Children: []testData{
   202  			{Recurse: false},
   203  		},
   204  	}
   205  	expected := `Root: Children`
   206  	err = templ.Execute(&b, data)
   207  	require.NoError(t, err)
   208  	assert.Equal(t, expected, b.String())
   209  
   210  	data = testData{
   211  		Name: "Root",
   212  		Children: []testData{
   213  			{Name: "Child1", Recurse: true, Children: []testData{{Name: "Child2"}}},
   214  		},
   215  	}
   216  
   217  	b.Reset()
   218  
   219  	expected = `Root: Child1: Children`
   220  
   221  	err = templ.Execute(&b, data)
   222  	require.NoError(t, err)
   223  
   224  	assert.Equal(t, expected, b.String())
   225  
   226  	data = testData{
   227  		Name: "Root",
   228  		Children: []testData{
   229  			{Name: "Child1", Recurse: false, Children: []testData{{Name: "Child2"}}},
   230  		},
   231  	}
   232  
   233  	b.Reset()
   234  
   235  	expected = `Root: Children`
   236  
   237  	err = templ.Execute(&b, data)
   238  	require.NoError(t, err)
   239  
   240  	assert.Equal(t, expected, b.String())
   241  }
   242  
   243  // Test that definitions are available to templates
   244  // TODO: should test also with the codeGenApp context
   245  
   246  // Test copyright definition
   247  func TestTemplates_DefinitionCopyright(t *testing.T) {
   248  	defer discardOutput()()
   249  
   250  	const copyright = `{{ .Copyright }}`
   251  
   252  	repo := NewRepository(nil)
   253  
   254  	err := repo.AddFile("copyright", copyright)
   255  	require.NoError(t, err)
   256  
   257  	templ, err := repo.Get("copyright")
   258  	require.NoError(t, err)
   259  	require.NotNil(t, templ)
   260  
   261  	opts := opts()
   262  	opts.Copyright = "My copyright clause"
   263  	expected := opts.Copyright
   264  
   265  	// executes template against model definitions
   266  	genModel, err := getModelEnvironment("../fixtures/codegen/todolist.models.yml", opts)
   267  	require.NoError(t, err)
   268  	require.NotNil(t, genModel)
   269  
   270  	rendered := bytes.NewBuffer(nil)
   271  	err = templ.Execute(rendered, genModel)
   272  	require.NoError(t, err)
   273  	assert.Equal(t, expected, rendered.String())
   274  
   275  	// executes template against operations definitions
   276  	genOperation, err := getOperationEnvironment("get", "/media/search", "../fixtures/codegen/instagram.yml", opts)
   277  	require.NoError(t, err)
   278  	require.NotNil(t, genOperation)
   279  
   280  	rendered.Reset()
   281  
   282  	err = templ.Execute(rendered, genOperation)
   283  	require.NoError(t, err)
   284  
   285  	assert.Equal(t, expected, rendered.String())
   286  }
   287  
   288  // Test TargetImportPath definition
   289  func TestTemplates_DefinitionTargetImportPath(t *testing.T) {
   290  	const targetImportPath = `{{ .TargetImportPath }}`
   291  	defer discardOutput()()
   292  
   293  	repo := NewRepository(nil)
   294  
   295  	err := repo.AddFile("targetimportpath", targetImportPath)
   296  	require.NoError(t, err)
   297  
   298  	templ, err := repo.Get("targetimportpath")
   299  	require.NoError(t, err)
   300  	require.NotNil(t, templ)
   301  
   302  	opts := opts()
   303  	// Non existing target would panic: to be tested too, but in another module
   304  	opts.Target = "../fixtures"
   305  	expected := "github.com/go-swagger/go-swagger/fixtures"
   306  
   307  	// executes template against model definitions
   308  	genModel, err := getModelEnvironment("../fixtures/codegen/todolist.models.yml", opts)
   309  	require.NoError(t, err)
   310  	require.NotNil(t, genModel)
   311  
   312  	rendered := bytes.NewBuffer(nil)
   313  	err = templ.Execute(rendered, genModel)
   314  	require.NoError(t, err)
   315  
   316  	assert.Equal(t, expected, rendered.String())
   317  
   318  	// executes template against operations definitions
   319  	genOperation, err := getOperationEnvironment("get", "/media/search", "../fixtures/codegen/instagram.yml", opts)
   320  	require.NoError(t, err)
   321  	require.NotNil(t, genOperation)
   322  
   323  	rendered.Reset()
   324  
   325  	err = templ.Execute(rendered, genOperation)
   326  	require.NoError(t, err)
   327  
   328  	assert.Equal(t, expected, rendered.String())
   329  }
   330  
   331  // Simulates a definition environment for model templates
   332  func getModelEnvironment(_ string, opts *GenOpts) (*GenDefinition, error) {
   333  	defer discardOutput()()
   334  
   335  	specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml")
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	definitions := specDoc.Spec().Definitions
   340  
   341  	for k, schema := range definitions {
   342  		genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   343  		if err != nil {
   344  			return nil, err
   345  		}
   346  		// One is enough
   347  		return genModel, nil
   348  	}
   349  	return nil, nil
   350  }
   351  
   352  // Simulates a definition environment for operation templates
   353  func getOperationEnvironment(operation string, path string, spec string, opts *GenOpts) (*GenOperation, error) {
   354  	defer discardOutput()()
   355  
   356  	b, err := methodPathOpBuilder(operation, path, spec)
   357  	if err != nil {
   358  		return nil, err
   359  	}
   360  	b.GenOpts = opts
   361  	g, err := b.MakeOperation()
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  	return &g, nil
   366  }
   367  
   368  // Exercises FuncMap
   369  // Just running basic tests to make sure the function map works and all functions are available as expected.
   370  // More complete unit tests are provided by go-openapi/swag.
   371  func TestTemplates_FuncMap(t *testing.T) {
   372  	defer discardOutput()()
   373  
   374  	funcTpl := testFuncTpl()
   375  
   376  	err := templates.AddFile("functpl", funcTpl)
   377  	require.NoError(t, err)
   378  
   379  	templ, err := templates.Get("functpl")
   380  	require.NoError(t, err)
   381  
   382  	opts := opts()
   383  	// executes template against model definitions
   384  	genModel, err := getModelEnvironment("../fixtures/codegen/todolist.models.yml", opts)
   385  	require.NoError(t, err)
   386  
   387  	genModel.DependsOn = []string{"x", "z"}
   388  	rendered := bytes.NewBuffer(nil)
   389  	err = templ.Execute(rendered, genModel)
   390  	require.NoError(t, err)
   391  
   392  	assert.Contains(t, rendered.String(), "Pascalize=WeArePoniesOfTheRoundTable\n")
   393  	assert.Contains(t, rendered.String(), "Snakize=we_are_ponies_of_the_round_table\n")
   394  	assert.Contains(t, rendered.String(), "Humanize=we are ponies of the round table\n")
   395  	assert.Contains(t, rendered.String(), "PluralizeFirstWord=ponies of the round table\n")
   396  	assert.Contains(t, rendered.String(), "PluralizeFirstOfOneWord=dwarves\n")
   397  	assert.Contains(t, rendered.String(), "PluralizeFirstOfNoWord=\n")
   398  	assert.Contains(t, rendered.String(), "DropPackage=suffix\n")
   399  	assert.Contains(t, rendered.String(), "DropNoPackage=suffix\n")
   400  	assert.Contains(t, rendered.String(), "DropEmptyPackage=\n")
   401  	assert.Contains(t, rendered.String(), "DropEmptyPackage=\n")
   402  	assert.Contains(t, rendered.String(), "ContainsString=true\n")
   403  	assert.Contains(t, rendered.String(), "DoesNotContainString=false\n")
   404  	assert.Contains(t, rendered.String(), "PadSurround1=-,-,-,padme,-,-,-,-,-,-,-,-\n")
   405  	assert.Contains(t, rendered.String(), "PadSurround2=padme,-,-,-,-,-,-,-,-,-,-,-\n")
   406  	assert.Contains(t, rendered.String(), `Json={"errors":"github.com/go-openapi/errors","runtime":"github.com/go-openapi/runtime","strfmt":"github.com/go-openapi/strfmt","swag":"github.com/go-openapi/swag","validate":"github.com/go-openapi/validate"}`)
   407  	assert.Contains(t, rendered.String(), "\"TargetImportPath\": \"github.com/go-swagger/go-swagger/generator\"")
   408  	assert.Contains(t, rendered.String(), "Snakize1=ending_in_os_name_linux_swagger\n")
   409  	assert.Contains(t, rendered.String(), "Snakize2=ending_in_arch_name_linux_amd64_swagger\n")
   410  	assert.Contains(t, rendered.String(), "Snakize3=ending_in_test_swagger\n")
   411  	assert.Contains(t, rendered.String(), "toPackage1=a/b-c/d_e\n")
   412  	assert.Contains(t, rendered.String(), "toPackage2=a.a/b_c/d_e\n")
   413  	assert.Contains(t, rendered.String(), "toPackage3=d_e\n")
   414  	assert.Contains(t, rendered.String(), "toPackage4=d_e\n")
   415  	assert.Contains(t, rendered.String(), "toPackageName=f_g\n")
   416  	assert.Contains(t, rendered.String(), "PascalizeSpecialChar1=Plus1\n")
   417  	assert.Contains(t, rendered.String(), "PascalizeSpecialChar2=Minus1\n")
   418  	assert.Contains(t, rendered.String(), "PascalizeSpecialChar3=Nr1\n")
   419  	assert.Contains(t, rendered.String(), "PascalizeSpecialChar4=Minus\n")
   420  	assert.Contains(t, rendered.String(), "PascalizeSpecialChar5=Plus\n")
   421  	assert.Contains(t, rendered.String(), "PascalizeCleanupEnumVariant1=Nr2Dot4Ghz")
   422  	assert.Contains(t, rendered.String(), "Dict=Pony of the round table\n")
   423  }
   424  
   425  // AddFile() global package function (protected vs unprotected)
   426  // Mostly unused in tests, since the Repository.AddFile()
   427  // is generally preferred.
   428  func TestTemplates_AddFile(t *testing.T) {
   429  	defer discardOutput()()
   430  
   431  	funcTpl := testFuncTpl()
   432  
   433  	// unprotected
   434  	err := AddFile("functpl", funcTpl)
   435  	require.NoError(t, err)
   436  
   437  	_, err = templates.Get("functpl")
   438  	require.NoError(t, err)
   439  
   440  	// protected
   441  	err = AddFile("schemabody", funcTpl)
   442  	require.Error(t, err)
   443  	assert.Contains(t, err.Error(), "cannot overwrite protected template")
   444  }
   445  
   446  // Test LoadDir
   447  func TestTemplates_LoadDir(t *testing.T) {
   448  	defer discardOutput()()
   449  
   450  	// Fails
   451  	err := templates.LoadDir("")
   452  	require.Error(t, err)
   453  	assert.Contains(t, err.Error(), "could not complete")
   454  
   455  	// Fails again (from any dir?)
   456  	err = templates.LoadDir("templates")
   457  	require.Error(t, err)
   458  	assert.Contains(t, err.Error(), "cannot overwrite protected template")
   459  
   460  	// TODO: success case
   461  	// To force a success, we need to empty the global list of protected
   462  	// templates...
   463  	origProtectedTemplates := protectedTemplates
   464  
   465  	defer func() {
   466  		// Restore variable initialized with package
   467  		protectedTemplates = origProtectedTemplates
   468  	}()
   469  
   470  	protectedTemplates = make(map[string]bool)
   471  	repo := NewRepository(FuncMapFunc(DefaultLanguageFunc()))
   472  	err = repo.LoadDir("templates")
   473  	require.NoError(t, err)
   474  }
   475  
   476  // Test LoadDir
   477  func TestTemplates_SetAllowOverride(t *testing.T) {
   478  	defer discardOutput()()
   479  
   480  	// adding protected file with allowOverride set to false fails
   481  	templates.SetAllowOverride(false)
   482  	err := templates.AddFile("schemabody", "some data")
   483  	require.Error(t, err)
   484  	assert.Contains(t, err.Error(), "cannot overwrite protected template schemabody")
   485  
   486  	// adding protected file with allowOverride set to true should not fail
   487  	templates.SetAllowOverride(true)
   488  	err = templates.AddFile("schemabody", "some data")
   489  	require.NoError(t, err)
   490  }
   491  
   492  // Test LoadContrib
   493  func TestTemplates_LoadContrib(t *testing.T) {
   494  	tests := []struct {
   495  		name      string
   496  		template  string
   497  		wantError bool
   498  	}{
   499  		{
   500  			name:      "None_existing_contributor_template",
   501  			template:  "NonExistingContributorTemplate",
   502  			wantError: true,
   503  		},
   504  		{
   505  			name:      "Existing_contributor",
   506  			template:  "stratoscale",
   507  			wantError: false,
   508  		},
   509  	}
   510  
   511  	for _, tt := range tests {
   512  		t.Run(tt.name, func(t *testing.T) {
   513  			err := templates.LoadContrib(tt.template)
   514  			if tt.wantError {
   515  				require.Error(t, err)
   516  			} else {
   517  				require.NoError(t, err)
   518  			}
   519  		})
   520  	}
   521  }
   522  
   523  // TODO: test error case in LoadDefaults()
   524  // test DumpTemplates()
   525  func TestTemplates_DumpTemplates(t *testing.T) {
   526  	var buf bytes.Buffer
   527  	defer captureOutput(&buf)()
   528  
   529  	templates.DumpTemplates()
   530  	assert.NotEmpty(t, buf)
   531  	// Sample output
   532  	assert.Contains(t, buf.String(), "## tupleSerializer")
   533  	assert.Contains(t, buf.String(), "Defined in `tupleserializer.gotmpl`")
   534  	assert.Contains(t, buf.String(), "####requires \n - schemaType")
   535  }
   536  
   537  func TestFuncMap_Pascalize(t *testing.T) {
   538  	assert.Equal(t, "Plus1", pascalize("+1"))
   539  	assert.Equal(t, "Plus", pascalize("+"))
   540  	assert.Equal(t, "Minus1", pascalize("-1"))
   541  	assert.Equal(t, "Minus", pascalize("-"))
   542  	assert.Equal(t, "Nr8", pascalize("8"))
   543  	assert.Equal(t, "Asterisk", pascalize("*"))
   544  	assert.Equal(t, "ForwardSlash", pascalize("/"))
   545  	assert.Equal(t, "EqualSign", pascalize("="))
   546  
   547  	assert.Equal(t, "Hello", pascalize("+hello"))
   548  
   549  	// other values from swag rules
   550  	assert.Equal(t, "At8", pascalize("@8"))
   551  	assert.Equal(t, "AtHello", pascalize("@hello"))
   552  	assert.Equal(t, "Bang8", pascalize("!8"))
   553  	assert.Equal(t, "At", pascalize("@"))
   554  
   555  	// # values
   556  	assert.Equal(t, "Hello", pascalize("#hello"))
   557  	assert.Equal(t, "BangHello", pascalize("#!hello"))
   558  	assert.Equal(t, "HashTag8", pascalize("#8"))
   559  	assert.Equal(t, "HashTag", pascalize("#"))
   560  
   561  	// single '_'
   562  	assert.Equal(t, "Nr", pascalize("_"))
   563  	assert.Equal(t, "Hello", pascalize("_hello"))
   564  
   565  	// remove spaces
   566  	assert.Equal(t, "HelloWorld", pascalize("# hello world"))
   567  	assert.Equal(t, "HashTag8HelloWorld", pascalize("# 8 hello world"))
   568  
   569  	assert.Equal(t, "Empty", pascalize(""))
   570  }
   571  
   572  func TestFuncMap_DropPackage(t *testing.T) {
   573  	assert.Equal(t, "trail", dropPackage("base.trail"))
   574  	assert.Equal(t, "trail", dropPackage("base.another.trail"))
   575  	assert.Equal(t, "trail", dropPackage("trail"))
   576  }
   577  
   578  func TestFuncMap_AsJSON(t *testing.T) {
   579  	for _, jsonFunc := range []func(interface{}) (string, error){
   580  		asJSON,
   581  		asPrettyJSON,
   582  	} {
   583  		res, err := jsonFunc(struct {
   584  			A string `json:"a"`
   585  			B int
   586  		}{A: "good", B: 3})
   587  		require.NoError(t, err)
   588  		assert.JSONEq(t, `{"a":"good","B":3}`, res)
   589  
   590  		_, err = jsonFunc(struct {
   591  			A string `json:"a"`
   592  			B func() string
   593  		}{A: "good", B: func() string { return "" }})
   594  		require.Error(t, err)
   595  	}
   596  }
   597  
   598  func TestFuncMap_Dict(t *testing.T) {
   599  	d, err := dict("a", "b", "c", "d")
   600  	require.NoError(t, err)
   601  	assert.Equal(t, map[string]interface{}{"a": "b", "c": "d"}, d)
   602  
   603  	// odd number of arguments
   604  	_, err = dict("a", "b", "c")
   605  	require.Error(t, err)
   606  
   607  	// none-string key
   608  	_, err = dict("a", "b", 3, "d")
   609  	require.Error(t, err)
   610  }
   611  
   612  func TestIsInteger(t *testing.T) {
   613  	var (
   614  		nilString *string
   615  		nilInt    *int
   616  		nilFloat  *float32
   617  	)
   618  
   619  	for _, anInteger := range []interface{}{
   620  		int8(4),
   621  		int16(4),
   622  		int32(4),
   623  		int64(4),
   624  		int(4),
   625  		swag.Int(4),
   626  		swag.Int32(4),
   627  		swag.Int64(4),
   628  		swag.Uint(4),
   629  		swag.Uint32(4),
   630  		swag.Uint64(4),
   631  		float32(12),
   632  		float64(12),
   633  		swag.Float32(12),
   634  		swag.Float64(12),
   635  		"12",
   636  		swag.String("12"),
   637  	} {
   638  		val := anInteger
   639  		require.Truef(t, isInteger(val), "expected %#v to be detected an integer value", val)
   640  	}
   641  
   642  	for _, notAnInteger := range []interface{}{
   643  		float32(12.5),
   644  		float64(12.5),
   645  		swag.Float32(12.5),
   646  		swag.Float64(12.5),
   647  		[]string{"a"},
   648  		struct{}{},
   649  		nil,
   650  		map[string]int{"a": 1},
   651  		"abc",
   652  		"2.34",
   653  		swag.String("2.34"),
   654  		nilString,
   655  		nilInt,
   656  		nilFloat,
   657  	} {
   658  		val := notAnInteger
   659  		require.Falsef(t, isInteger(val), "did not expect %#v to be detected an integer value", val)
   660  	}
   661  }
   662  
   663  func TestGt0(t *testing.T) {
   664  	require.True(t, gt0(swag.Int64(1)))
   665  	require.False(t, gt0(swag.Int64(0)))
   666  	require.False(t, gt0(nil))
   667  }
   668  
   669  func TestIssue2821(t *testing.T) {
   670  	tpl := `
   671  Pascalize={{ pascalize . }}
   672  Camelize={{ camelize . }}
   673  `
   674  
   675  	require.NoError(t,
   676  		templates.AddFile("functpl", tpl),
   677  	)
   678  
   679  	compiled, err := templates.Get("functpl")
   680  	require.NoError(t, err)
   681  
   682  	rendered := bytes.NewBuffer(nil)
   683  	require.NoError(t,
   684  		compiled.Execute(rendered, "get$ref"),
   685  	)
   686  
   687  	assert.Contains(t, rendered.String(), "Pascalize=GetDollarRef\n")
   688  	assert.Contains(t, rendered.String(), "Camelize=getDollarRef\n")
   689  }