github.com/AngusLu/go-swagger@v0.28.0/generator/operation_test.go (about)

     1  // Copyright 2015 go-swagger maintainers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package generator
    16  
    17  import (
    18  	"bytes"
    19  	"errors"
    20  	"io/ioutil"
    21  	"os"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	"github.com/go-openapi/analysis"
    26  	"github.com/go-openapi/loads"
    27  	"github.com/go-openapi/spec"
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  func TestUniqueOperationNameMangling(t *testing.T) {
    33  	doc, err := loads.Spec("../fixtures/bugs/2213/fixture-2213.yaml")
    34  	require.NoError(t, err)
    35  	analyzed := analysis.New(doc.Spec())
    36  	ops := gatherOperations(analyzed, nil)
    37  	assert.Contains(t, ops, "GetFoo")
    38  	assert.Contains(t, ops, "GetAFoo")
    39  }
    40  
    41  func TestUniqueOperationNames(t *testing.T) {
    42  	doc, err := loads.Spec("../fixtures/codegen/todolist.simple.yml")
    43  	require.NoError(t, err)
    44  
    45  	sp := doc.Spec()
    46  	sp.Paths.Paths["/tasks"].Post.ID = "saveTask"
    47  	sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask")
    48  	sp.Paths.Paths["/tasks/{id}"].Put.ID = "saveTask"
    49  	sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask")
    50  	analyzed := analysis.New(sp)
    51  
    52  	ops := gatherOperations(analyzed, nil)
    53  	assert.Len(t, ops, 6)
    54  	_, exists := ops["saveTask"]
    55  	assert.True(t, exists)
    56  	_, exists = ops["PutTasksID"]
    57  	assert.True(t, exists)
    58  }
    59  
    60  func TestEmptyOperationNames(t *testing.T) {
    61  	doc, err := loads.Spec("../fixtures/codegen/todolist.simple.yml")
    62  	require.NoError(t, err)
    63  
    64  	sp := doc.Spec()
    65  	sp.Paths.Paths["/tasks"].Post.ID = ""
    66  	sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask")
    67  	sp.Paths.Paths["/tasks/{id}"].Put.ID = ""
    68  	sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask")
    69  	analyzed := analysis.New(sp)
    70  
    71  	ops := gatherOperations(analyzed, nil)
    72  	assert.Len(t, ops, 6)
    73  	_, exists := ops["PostTasks"]
    74  	assert.True(t, exists)
    75  	_, exists = ops["PutTasksID"]
    76  	assert.True(t, exists)
    77  }
    78  
    79  func TestMakeResponseHeader(t *testing.T) {
    80  	b, err := opBuilder("getTasks", "")
    81  	require.NoError(t, err)
    82  
    83  	hdr := findResponseHeader(&b.Operation, 200, "X-Rate-Limit")
    84  	gh, er := b.MakeHeader("a", "X-Rate-Limit", *hdr)
    85  	require.NoError(t, er)
    86  
    87  	assert.True(t, gh.IsPrimitive)
    88  	assert.Equal(t, "int32", gh.GoType)
    89  	assert.Equal(t, "X-Rate-Limit", gh.Name)
    90  }
    91  
    92  func TestMakeResponseHeaderDefaultValues(t *testing.T) {
    93  	b, err := opBuilder("getTasks", "")
    94  	require.NoError(t, err)
    95  
    96  	var testCases = []struct {
    97  		name         string      // input
    98  		typeStr      string      // expected type
    99  		defaultValue interface{} // expected result
   100  	}{
   101  		{"Access-Control-Allow-Origin", "string", "*"},
   102  		{"X-Rate-Limit", "int32", nil},
   103  		{"X-Rate-Limit-Remaining", "int32", float64(42)},
   104  		{"X-Rate-Limit-Reset", "int32", "1449875311"},
   105  		{"X-Rate-Limit-Reset-Human", "string", "3 days"},
   106  		{"X-Rate-Limit-Reset-Human-Number", "string", float64(3)},
   107  	}
   108  
   109  	for _, tc := range testCases {
   110  		hdr := findResponseHeader(&b.Operation, 200, tc.name)
   111  		require.NotNil(t, hdr)
   112  
   113  		gh, er := b.MakeHeader("a", tc.name, *hdr)
   114  		require.NoError(t, er)
   115  
   116  		assert.True(t, gh.IsPrimitive)
   117  		assert.Equal(t, tc.typeStr, gh.GoType)
   118  		assert.Equal(t, tc.name, gh.Name)
   119  		assert.Exactly(t, tc.defaultValue, gh.Default)
   120  	}
   121  }
   122  
   123  func TestMakeResponse(t *testing.T) {
   124  	b, err := opBuilder("getTasks", "")
   125  	require.NoError(t, err)
   126  
   127  	resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
   128  	resolver.KnownDefs = make(map[string]struct{})
   129  	for k := range b.Doc.Spec().Definitions {
   130  		resolver.KnownDefs[k] = struct{}{}
   131  	}
   132  	gO, err := b.MakeResponse("a", "getTasksSuccess", true, resolver, 200, b.Operation.Responses.StatusCodeResponses[200])
   133  	require.NoError(t, err)
   134  
   135  	assert.Len(t, gO.Headers, 6)
   136  	assert.NotNil(t, gO.Schema)
   137  	assert.True(t, gO.Schema.IsArray)
   138  	assert.NotNil(t, gO.Schema.Items)
   139  	assert.False(t, gO.Schema.IsAnonymous)
   140  	assert.Equal(t, "[]*models.Task", gO.Schema.GoType)
   141  }
   142  
   143  func TestMakeResponse_WithAllOfSchema(t *testing.T) {
   144  	b, err := methodPathOpBuilder("get", "/media/search", "../fixtures/codegen/instagram.yml")
   145  	require.NoError(t, err)
   146  
   147  	resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
   148  	resolver.KnownDefs = make(map[string]struct{})
   149  	for k := range b.Doc.Spec().Definitions {
   150  		resolver.KnownDefs[k] = struct{}{}
   151  	}
   152  	gO, err := b.MakeResponse("a", "get /media/search", true, resolver, 200, b.Operation.Responses.StatusCodeResponses[200])
   153  	require.NoError(t, err)
   154  
   155  	require.NotNil(t, gO.Schema)
   156  	assert.Equal(t, "GetMediaSearchBody", gO.Schema.GoType)
   157  
   158  	require.NotEmpty(t, b.ExtraSchemas)
   159  	body := b.ExtraSchemas["GetMediaSearchBody"]
   160  	require.NotEmpty(t, body.Properties)
   161  
   162  	prop := body.Properties[0]
   163  	assert.Equal(t, "data", prop.Name)
   164  	// is in models only when definition is flattened: otherwise, ExtraSchema is rendered in operations package
   165  	assert.Equal(t, "[]*GetMediaSearchBodyDataItems0", prop.GoType)
   166  
   167  	items := b.ExtraSchemas["GetMediaSearchBodyDataItems0"]
   168  	require.NotEmpty(t, items.AllOf)
   169  
   170  	media := items.AllOf[0]
   171  	// expect #definitions/media to be captured and reused by ExtraSchema
   172  	assert.Equal(t, "models.Media", media.GoType)
   173  }
   174  
   175  func TestMakeOperationParam(t *testing.T) {
   176  	b, err := opBuilder("getTasks", "")
   177  	require.NoError(t, err)
   178  
   179  	resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
   180  	gO, err := b.MakeParameter("a", resolver, b.Operation.Parameters[0], nil)
   181  	require.NoError(t, err)
   182  
   183  	assert.Equal(t, "size", gO.Name)
   184  	assert.True(t, gO.IsPrimitive)
   185  }
   186  
   187  func TestMakeOperationParamItem(t *testing.T) {
   188  	b, err := opBuilder("arrayQueryParams", "../fixtures/codegen/todolist.arrayquery.yml")
   189  	require.NoError(t, err)
   190  	resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc}
   191  	gO, err := b.MakeParameterItem("a", "siString", "ii", "siString", "a.SiString", "query", resolver, b.Operation.Parameters[1].Items, nil)
   192  	require.NoError(t, err)
   193  	assert.Nil(t, gO.Parent)
   194  	assert.True(t, gO.IsPrimitive)
   195  }
   196  
   197  func TestMakeOperation(t *testing.T) {
   198  	b, err := opBuilder("getTasks", "")
   199  	require.NoError(t, err)
   200  	gO, err := b.MakeOperation()
   201  	require.NoError(t, err)
   202  	assert.Equal(t, "getTasks", gO.Name)
   203  	assert.Equal(t, "GET", gO.Method)
   204  	assert.Equal(t, "/tasks", gO.Path)
   205  	assert.Len(t, gO.Params, 2)
   206  	assert.Len(t, gO.Responses, 1)
   207  	assert.NotNil(t, gO.DefaultResponse)
   208  	assert.NotNil(t, gO.SuccessResponse)
   209  }
   210  
   211  func TestRenderOperation_InstagramSearch(t *testing.T) {
   212  	defer discardOutput()()
   213  
   214  	b, err := methodPathOpBuilder("get", "/media/search", "../fixtures/codegen/instagram.yml")
   215  	require.NoError(t, err)
   216  
   217  	gO, err := b.MakeOperation()
   218  	require.NoError(t, err)
   219  
   220  	buf := bytes.NewBuffer(nil)
   221  	opt := opts()
   222  
   223  	require.NoError(t, opt.templates.MustGet("serverOperation").Execute(buf, gO))
   224  
   225  	ff, err := opt.LanguageOpts.FormatContent("operation.go", buf.Bytes())
   226  	require.NoErrorf(t, err, buf.String())
   227  
   228  	res := string(ff)
   229  	assertInCode(t, "type GetMediaSearchOKBody struct {", res)
   230  	// codegen does not assumes objects are only in models
   231  	// this is inlined
   232  	assertInCode(t, "Data []*GetMediaSearchOKBodyDataItems0 `json:\"data\"`", res)
   233  	assertInCode(t, "type GetMediaSearchOKBodyDataItems0 struct {", res)
   234  	// this is a definition: expect this definition to be reused from the models pkg
   235  	assertInCode(t, "models.Media", res)
   236  
   237  	buf = bytes.NewBuffer(nil)
   238  	require.NoError(t, opt.templates.MustGet("serverResponses").Execute(buf, gO))
   239  
   240  	ff, err = opt.LanguageOpts.FormatContent("response.go", buf.Bytes())
   241  	require.NoErrorf(t, err, buf.String())
   242  
   243  	res = string(ff)
   244  	// codegen does not assumes objects are only in models
   245  	assertInCode(t, "type GetMediaSearchOK struct {", res)
   246  	assertInCode(t, "GetMediaSearchOKBody", res)
   247  
   248  	b, err = methodPathOpBuilderWithFlatten("get", "/media/search", "../fixtures/codegen/instagram.yml")
   249  	require.NoError(t, err)
   250  
   251  	gO, err = b.MakeOperation()
   252  	require.NoError(t, err)
   253  
   254  	buf = bytes.NewBuffer(nil)
   255  	opt = opts()
   256  	require.NoError(t, opt.templates.MustGet("serverOperation").Execute(buf, gO))
   257  
   258  	ff, err = opt.LanguageOpts.FormatContent("operation.go", buf.Bytes())
   259  	require.NoErrorf(t, err, buf.String())
   260  
   261  	res = string(ff)
   262  	assertNotInCode(t, "DataItems0", res)
   263  	assertNotInCode(t, "models", res)
   264  
   265  	buf = bytes.NewBuffer(nil)
   266  	require.NoError(t, opt.templates.MustGet("serverResponses").Execute(buf, gO))
   267  
   268  	ff, err = opt.LanguageOpts.FormatContent("operation.go", buf.Bytes())
   269  	require.NoErrorf(t, err, buf.String())
   270  
   271  	res = string(ff)
   272  	assertInCode(t, "Payload *models.GetMediaSearchOKBody", res)
   273  }
   274  
   275  func methodPathOpBuilder(method, path, fname string) (codeGenOpBuilder, error) {
   276  	defer discardOutput()()
   277  
   278  	if fname == "" {
   279  		fname = "../fixtures/codegen/todolist.simple.yml"
   280  	}
   281  	o := opts()
   282  	o.Spec = fname
   283  	specDoc, analyzed, err := o.analyzeSpec()
   284  	if err != nil {
   285  		return codeGenOpBuilder{}, err
   286  	}
   287  	op, ok := analyzed.OperationFor(method, path)
   288  	if !ok {
   289  		return codeGenOpBuilder{}, errors.New("No operation could be found for " + method + " " + path)
   290  	}
   291  
   292  	return codeGenOpBuilder{
   293  		Name:          method + " " + path,
   294  		Method:        method,
   295  		Path:          path,
   296  		APIPackage:    "restapi",
   297  		ModelsPackage: "models",
   298  		Principal:     "models.User",
   299  		Target:        ".",
   300  		Operation:     *op,
   301  		Doc:           specDoc,
   302  		Analyzed:      analyzed,
   303  		Authed:        false,
   304  		ExtraSchemas:  make(map[string]GenSchema),
   305  		GenOpts:       o,
   306  	}, nil
   307  }
   308  
   309  // methodPathOpBuilderWithFlatten prepares an operation build based on method and path, with spec full flattening
   310  func methodPathOpBuilderWithFlatten(method, path, fname string) (codeGenOpBuilder, error) {
   311  	defer discardOutput()()
   312  
   313  	if fname == "" {
   314  		fname = "../fixtures/codegen/todolist.simple.yml"
   315  	}
   316  
   317  	o := opBuildGetOpts(fname, true, false) // flatten: true, minimal: false
   318  	o.Spec = fname
   319  	specDoc, analyzed, err := o.analyzeSpec()
   320  	if err != nil {
   321  		return codeGenOpBuilder{}, err
   322  	}
   323  	op, ok := analyzed.OperationFor(method, path)
   324  	if !ok {
   325  		return codeGenOpBuilder{}, errors.New("No operation could be found for " + method + " " + path)
   326  	}
   327  
   328  	return codeGenOpBuilder{
   329  		Name:          method + " " + path,
   330  		Method:        method,
   331  		Path:          path,
   332  		APIPackage:    "restapi",
   333  		ModelsPackage: "models",
   334  		Principal:     "models.User",
   335  		Target:        ".",
   336  		Operation:     *op,
   337  		Doc:           specDoc,
   338  		Analyzed:      analyzed,
   339  		Authed:        false,
   340  		ExtraSchemas:  make(map[string]GenSchema),
   341  		GenOpts:       opts(),
   342  	}, nil
   343  }
   344  
   345  // opBuilderWithOpts prepares the making of an operation with spec flattening options
   346  func opBuilderWithOpts(name, fname string, o *GenOpts) (codeGenOpBuilder, error) {
   347  	defer discardOutput()()
   348  
   349  	if fname == "" {
   350  		// default fixture
   351  		fname = "../fixtures/codegen/todolist.simple.yml"
   352  	}
   353  
   354  	o.Spec = fname
   355  	specDoc, analyzed, err := o.analyzeSpec()
   356  	if err != nil {
   357  		return codeGenOpBuilder{}, err
   358  	}
   359  
   360  	method, path, op, ok := analyzed.OperationForName(name)
   361  	if !ok {
   362  		return codeGenOpBuilder{}, errors.New("No operation could be found for " + name)
   363  	}
   364  
   365  	return codeGenOpBuilder{
   366  		Name:          name,
   367  		Method:        method,
   368  		Path:          path,
   369  		BasePath:      specDoc.BasePath(),
   370  		APIPackage:    "restapi",
   371  		ModelsPackage: "models",
   372  		Principal:     "models.User",
   373  		Target:        ".",
   374  		Operation:     *op,
   375  		Doc:           specDoc,
   376  		Analyzed:      analyzed,
   377  		Authed:        false,
   378  		ExtraSchemas:  make(map[string]GenSchema),
   379  		GenOpts:       o,
   380  	}, nil
   381  }
   382  
   383  func opBuildGetOpts(specName string, withFlatten bool, withMinimalFlatten bool) (opts *GenOpts) {
   384  	opts = &GenOpts{}
   385  	opts.ValidateSpec = true
   386  	opts.FlattenOpts = &analysis.FlattenOpts{
   387  		Expand:  !withFlatten,
   388  		Minimal: withMinimalFlatten,
   389  	}
   390  	opts.Spec = specName
   391  	if err := opts.EnsureDefaults(); err != nil {
   392  		panic("Cannot initialize GenOpts")
   393  	}
   394  	return
   395  }
   396  
   397  // opBuilderWithFlatten prepares the making of an operation with spec full flattening prior to rendering
   398  func opBuilderWithFlatten(name, fname string) (codeGenOpBuilder, error) {
   399  	o := opBuildGetOpts(fname, true, false) // flatten: true, minimal: false
   400  	return opBuilderWithOpts(name, fname, o)
   401  }
   402  
   403  /*
   404  // opBuilderWithMinimalFlatten prepares the making of an operation with spec minimal flattening prior to rendering
   405  func opBuilderWithMinimalFlatten(name, fname string) (codeGenOpBuilder, error) {
   406  	o := opBuildGetOpts(fname, true, true) // flatten: true, minimal: true
   407  	return opBuilderWithOpts(name, fname, o)
   408  }
   409  */
   410  
   411  // opBuilderWithExpand prepares the making of an operation with spec expansion prior to rendering
   412  func opBuilderWithExpand(name, fname string) (codeGenOpBuilder, error) {
   413  	o := opBuildGetOpts(fname, false, false) // flatten: false => expand
   414  	return opBuilderWithOpts(name, fname, o)
   415  }
   416  
   417  // opBuilder prepares the making of an operation with spec minimal flattening (default for CLI)
   418  func opBuilder(name, fname string) (codeGenOpBuilder, error) {
   419  	o := opBuildGetOpts(fname, true, true) // flatten:true, minimal: true
   420  	// some fixtures do not fully validate - skip this
   421  	o.ValidateSpec = false
   422  	return opBuilderWithOpts(name, fname, o)
   423  }
   424  
   425  func findResponseHeader(op *spec.Operation, code int, name string) *spec.Header {
   426  	resp := op.Responses.Default
   427  	if code > 0 {
   428  		bb, ok := op.Responses.StatusCodeResponses[code]
   429  		if ok {
   430  			resp = &bb
   431  		}
   432  	}
   433  
   434  	if resp == nil {
   435  		return nil
   436  	}
   437  
   438  	hdr, ok := resp.Headers[name]
   439  	if !ok {
   440  		return nil
   441  	}
   442  
   443  	return &hdr
   444  }
   445  
   446  func TestDateFormat_Spec1(t *testing.T) {
   447  	b, err := opBuilder("putTesting", "../fixtures/bugs/193/spec1.json")
   448  	require.NoError(t, err)
   449  
   450  	op, err := b.MakeOperation()
   451  	require.NoError(t, err)
   452  
   453  	buf := bytes.NewBuffer(nil)
   454  	opts := opts()
   455  	opts.defaultsEnsured = false
   456  	opts.IsClient = true
   457  	require.NoError(t, opts.EnsureDefaults())
   458  
   459  	require.NoError(t, opts.templates.MustGet("clientParameter").Execute(buf, op))
   460  
   461  	ff, err := opts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes())
   462  	require.NoErrorf(t, err, buf.String())
   463  
   464  	assertInCode(t, "frTestingThis.String()", string(ff))
   465  }
   466  
   467  func TestDateFormat_Spec2(t *testing.T) {
   468  	b, err := opBuilder("putTesting", "../fixtures/bugs/193/spec2.json")
   469  	require.NoError(t, err)
   470  
   471  	op, err := b.MakeOperation()
   472  	require.NoError(t, err)
   473  
   474  	buf := bytes.NewBuffer(nil)
   475  	opts := opts()
   476  	opts.defaultsEnsured = false
   477  	opts.IsClient = true
   478  	require.NoError(t, opts.EnsureDefaults())
   479  
   480  	require.NoError(t, opts.templates.MustGet("clientParameter").Execute(buf, op))
   481  
   482  	ff, err := opts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes())
   483  	require.NoErrorf(t, err, buf.String())
   484  
   485  	res := string(ff)
   486  	assertInCode(t, "o.TestingThis != nil {", res)
   487  	assertInCode(t, "joinedTestingThis := o.bindParamTestingThis(reg)", res)
   488  	assertInCode(t, `if err := r.SetFormParam("testingThis", joinedTestingThis...); err != nil {`, res)
   489  	assertInCode(t, "func (o *PutTestingParams) bindParamTestingThis(formats strfmt.Registry) []string {", res)
   490  	assertInCode(t, "testingThisIR := o.TestingThis", res)
   491  	assertInCode(t, "var testingThisIC []string", res)
   492  	assertInCode(t, "for _, testingThisIIR := range testingThisIR {", res)
   493  	assertInCode(t, "testingThisIIV := testingThisIIR.String()", res)
   494  	assertInCode(t, "testingThisIC = append(testingThisIC, testingThisIIV)", res)
   495  	assertInCode(t, `testingThisIS := swag.JoinByFormat(testingThisIC, "")`, res)
   496  	assertInCode(t, "return testingThisIS", res)
   497  }
   498  
   499  func TestBuilder_Issue1703(t *testing.T) {
   500  	defer discardOutput()()
   501  
   502  	dr := testCwd(t)
   503  
   504  	opts := &GenOpts{
   505  		Spec:              filepath.FromSlash("../fixtures/codegen/existing-model.yml"),
   506  		IncludeModel:      true,
   507  		IncludeHandler:    true,
   508  		IncludeParameters: true,
   509  		IncludeResponses:  true,
   510  		IncludeMain:       true,
   511  		APIPackage:        "restapi",
   512  		ModelPackage:      "model",
   513  		ServerPackage:     "server",
   514  		ClientPackage:     "client",
   515  		Target:            dr,
   516  	}
   517  	require.NoError(t, opts.EnsureDefaults())
   518  
   519  	appGen, err := newAppGenerator("x-go-type-import-bug", nil, nil, opts)
   520  	require.NoError(t, err)
   521  
   522  	op, err := appGen.makeCodegenApp()
   523  	require.NoError(t, err)
   524  
   525  	for _, o := range op.Operations {
   526  		buf := bytes.NewBuffer(nil)
   527  		require.NoError(t, opts.templates.MustGet("serverResponses").Execute(buf, o))
   528  
   529  		ff, err := appGen.GenOpts.LanguageOpts.FormatContent("response.go", buf.Bytes())
   530  		require.NoErrorf(t, err, buf.String())
   531  
   532  		assertInCode(t, "jwk \"github.com/user/package\"", string(ff))
   533  	}
   534  }
   535  
   536  func TestBuilder_Issue287(t *testing.T) {
   537  	defer discardOutput()()
   538  
   539  	dr := testCwd(t)
   540  
   541  	opts := &GenOpts{
   542  		Spec:              filepath.FromSlash("../fixtures/bugs/287/swagger.yml"),
   543  		IncludeModel:      true,
   544  		IncludeHandler:    true,
   545  		IncludeParameters: true,
   546  		IncludeResponses:  true,
   547  		IncludeMain:       true,
   548  		APIPackage:        "restapi",
   549  		ModelPackage:      "model",
   550  		ServerPackage:     "server",
   551  		ClientPackage:     "client",
   552  		Target:            dr,
   553  	}
   554  	require.NoError(t, opts.EnsureDefaults())
   555  
   556  	appGen, err := newAppGenerator("plainTexter", nil, nil, opts)
   557  	require.NoError(t, err)
   558  
   559  	op, err := appGen.makeCodegenApp()
   560  	require.NoError(t, err)
   561  
   562  	buf := bytes.NewBuffer(nil)
   563  	require.NoError(t, opts.templates.MustGet("serverBuilder").Execute(buf, op))
   564  
   565  	ff, err := appGen.GenOpts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes())
   566  	require.NoErrorf(t, err, buf.String())
   567  
   568  	assertInCode(t, "case \"text/plain\":", string(ff))
   569  }
   570  
   571  func TestBuilder_Issue465(t *testing.T) {
   572  	defer discardOutput()()
   573  
   574  	dr := testCwd(t)
   575  
   576  	opts := &GenOpts{
   577  		Spec:              filepath.FromSlash("../fixtures/bugs/465/swagger.yml"),
   578  		IncludeModel:      true,
   579  		IncludeHandler:    true,
   580  		IncludeParameters: true,
   581  		IncludeResponses:  true,
   582  		IncludeMain:       true,
   583  		APIPackage:        "restapi",
   584  		ModelPackage:      "model",
   585  		ServerPackage:     "server",
   586  		ClientPackage:     "client",
   587  		Target:            dr,
   588  		IsClient:          true,
   589  	}
   590  	require.NoError(t, opts.EnsureDefaults())
   591  
   592  	appGen, err := newAppGenerator("plainTexter", nil, nil, opts)
   593  	require.NoError(t, err)
   594  
   595  	op, err := appGen.makeCodegenApp()
   596  	require.NoError(t, err)
   597  
   598  	buf := bytes.NewBuffer(nil)
   599  	require.NoError(t, opts.templates.MustGet("clientFacade").Execute(buf, op))
   600  
   601  	ff, err := appGen.GenOpts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes())
   602  	require.NoErrorf(t, err, buf.String())
   603  
   604  	assertInCode(t, "/v1/fancyAPI", string(ff))
   605  }
   606  
   607  func TestBuilder_Issue500(t *testing.T) {
   608  	defer discardOutput()()
   609  
   610  	dr := testCwd(t)
   611  
   612  	opts := &GenOpts{
   613  		Spec:              filepath.FromSlash("../fixtures/bugs/500/swagger.yml"),
   614  		IncludeModel:      true,
   615  		IncludeHandler:    true,
   616  		IncludeParameters: true,
   617  		IncludeResponses:  true,
   618  		IncludeMain:       true,
   619  		APIPackage:        "restapi",
   620  		ModelPackage:      "model",
   621  		ServerPackage:     "server",
   622  		ClientPackage:     "client",
   623  		Target:            dr,
   624  	}
   625  	require.NoError(t, opts.EnsureDefaults())
   626  
   627  	appGen, err := newAppGenerator("multiTags", nil, nil, opts)
   628  	require.NoError(t, err)
   629  
   630  	op, err := appGen.makeCodegenApp()
   631  	require.NoError(t, err)
   632  
   633  	buf := bytes.NewBuffer(nil)
   634  	require.NoError(t, opts.templates.MustGet("serverBuilder").Execute(buf, op))
   635  
   636  	ff, err := appGen.GenOpts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes())
   637  	require.NoErrorf(t, err, buf.String())
   638  
   639  	res := string(ff)
   640  	assertNotInCode(t, `o.handlers["GET"]["/payment/{invoice_id}/payments/{payment_id}"] = NewGetPaymentByID(o.context, o.GetPaymentByIDHandler)`, res)
   641  	assertInCode(t, `o.handlers["GET"]["/payment/{invoice_id}/payments/{payment_id}"] = invoices.NewGetPaymentByID(o.context, o.InvoicesGetPaymentByIDHandler)`, res)
   642  }
   643  
   644  func TestGenClient_IllegalBOM(t *testing.T) {
   645  	b, err := methodPathOpBuilder("get", "/v3/attachments/{attachmentId}", "../fixtures/bugs/727/swagger.json")
   646  	require.NoError(t, err)
   647  
   648  	op, err := b.MakeOperation()
   649  	require.NoError(t, err)
   650  
   651  	buf := bytes.NewBuffer(nil)
   652  	opts := opts()
   653  	opts.defaultsEnsured = false
   654  	opts.IsClient = true
   655  	require.NoError(t, opts.EnsureDefaults())
   656  
   657  	require.NoError(t, opts.templates.MustGet("clientResponse").Execute(buf, op))
   658  }
   659  
   660  func TestGenClient_CustomFormatPath(t *testing.T) {
   661  	b, err := methodPathOpBuilder("get", "/mosaic/experimental/series/{SeriesId}/mosaics", "../fixtures/bugs/789/swagger.yml")
   662  	require.NoError(t, err)
   663  
   664  	op, err := b.MakeOperation()
   665  	require.NoError(t, err)
   666  
   667  	buf := bytes.NewBuffer(nil)
   668  	opts := opts()
   669  	opts.defaultsEnsured = false
   670  	opts.IsClient = true
   671  	require.NoError(t, opts.EnsureDefaults())
   672  
   673  	require.NoError(t, opts.templates.MustGet("clientParameter").Execute(buf, op))
   674  
   675  	assertInCode(t, `if err := r.SetPathParam("SeriesId", o.SeriesID.String()); err != nil`, buf.String())
   676  }
   677  
   678  func TestGenClient_Issue733(t *testing.T) {
   679  	b, err := opBuilder("get_characters_character_id_mail_mail_id", "../fixtures/bugs/733/swagger.json")
   680  	require.NoError(t, err)
   681  
   682  	op, err := b.MakeOperation()
   683  	require.NoError(t, err)
   684  
   685  	buf := bytes.NewBuffer(nil)
   686  	opts := opts()
   687  	opts.defaultsEnsured = false
   688  	opts.IsClient = true
   689  	require.NoError(t, opts.EnsureDefaults())
   690  
   691  	require.NoError(t, opts.templates.MustGet("clientResponse").Execute(buf, op))
   692  
   693  	assertInCode(t, "Labels []*int64 `json:\"labels\"`", buf.String())
   694  }
   695  
   696  func TestGenServerIssue890_ValidationTrueFlatteningTrue(t *testing.T) {
   697  	defer discardOutput()()
   698  
   699  	dr := testCwd(t)
   700  
   701  	opts := &GenOpts{
   702  		Spec:              filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"),
   703  		IncludeModel:      true,
   704  		IncludeHandler:    true,
   705  		IncludeParameters: true,
   706  		IncludeResponses:  true,
   707  		IncludeMain:       true,
   708  		ValidateSpec:      true,
   709  		APIPackage:        "restapi",
   710  		ModelPackage:      "model",
   711  		ServerPackage:     "server",
   712  		ClientPackage:     "client",
   713  		Target:            dr,
   714  		IsClient:          true,
   715  	}
   716  
   717  	// Testing Server Generation
   718  	require.NoError(t, opts.EnsureDefaults())
   719  
   720  	// Full flattening
   721  	opts.FlattenOpts.Expand = false
   722  	opts.FlattenOpts.Minimal = false
   723  	appGen, err := newAppGenerator("JsonRefOperation", nil, nil, opts)
   724  	require.NoError(t, err)
   725  
   726  	op, err := appGen.makeCodegenApp()
   727  	require.NoError(t, err)
   728  
   729  	buf := bytes.NewBuffer(nil)
   730  	require.NoError(t, opts.templates.MustGet("serverOperation").Execute(buf, op.Operations[0]))
   731  
   732  	filecontent, err := appGen.GenOpts.LanguageOpts.FormatContent("operation.go", buf.Bytes())
   733  	require.NoErrorf(t, err, buf.String())
   734  
   735  	res := string(filecontent)
   736  	assertInCode(t, "GetHealthCheck", res)
   737  }
   738  
   739  func TestGenClientIssue890_ValidationTrueFlatteningTrue(t *testing.T) {
   740  	defer discardOutput()()
   741  
   742  	dr := testCwd(t)
   743  	defer func() {
   744  		_ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi"))
   745  	}()
   746  
   747  	opts := testGenOpts()
   748  	opts.Spec = "../fixtures/bugs/890/swagger.yaml"
   749  	opts.ValidateSpec = true
   750  	opts.FlattenOpts.Minimal = false
   751  
   752  	// Testing this is enough as there is only one operation which is specified as $ref.
   753  	// If this doesn't get resolved then there will be an error definitely.
   754  	require.NoError(t, GenerateClient("foo", nil, nil, opts))
   755  }
   756  
   757  func TestGenServerIssue890_ValidationFalseFlattenTrue(t *testing.T) {
   758  	defer discardOutput()()
   759  
   760  	dr := testCwd(t)
   761  
   762  	opts := &GenOpts{
   763  		Spec:              filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"),
   764  		IncludeModel:      true,
   765  		IncludeHandler:    true,
   766  		IncludeParameters: true,
   767  		IncludeResponses:  true,
   768  		IncludeMain:       true,
   769  		APIPackage:        "restapi",
   770  		ModelPackage:      "model",
   771  		ServerPackage:     "server",
   772  		ClientPackage:     "client",
   773  		Target:            dr,
   774  		IsClient:          true,
   775  	}
   776  
   777  	// Testing Server Generation
   778  	require.NoError(t, opts.EnsureDefaults())
   779  
   780  	// full flattening
   781  	opts.FlattenOpts.Minimal = false
   782  	appGen, err := newAppGenerator("JsonRefOperation", nil, nil, opts)
   783  	require.NoError(t, err)
   784  
   785  	op, err := appGen.makeCodegenApp()
   786  	require.NoError(t, err)
   787  
   788  	buf := bytes.NewBuffer(nil)
   789  	err = opts.templates.MustGet("serverOperation").Execute(buf, op.Operations[0])
   790  	require.NoError(t, err)
   791  
   792  	filecontent, err := appGen.GenOpts.LanguageOpts.FormatContent("operation.go", buf.Bytes())
   793  	require.NoErrorf(t, err, buf.String())
   794  
   795  	res := string(filecontent)
   796  	assertInCode(t, "GetHealthCheck", res)
   797  }
   798  
   799  func TestGenClientIssue890_ValidationFalseFlatteningTrue(t *testing.T) {
   800  	defer discardOutput()()
   801  
   802  	dr := testCwd(t)
   803  	defer func() {
   804  		_ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi"))
   805  	}()
   806  
   807  	opts := testGenOpts()
   808  	opts.Spec = "../fixtures/bugs/890/swagger.yaml"
   809  	opts.ValidateSpec = false
   810  	// full flattening
   811  	opts.FlattenOpts.Minimal = false
   812  	// Testing this is enough as there is only one operation which is specified as $ref.
   813  	// If this doesn't get resolved then there will be an error definitely.
   814  	assert.NoError(t, GenerateClient("foo", nil, nil, opts))
   815  }
   816  
   817  func TestGenServerIssue890_ValidationFalseFlattenFalse(t *testing.T) {
   818  	defer discardOutput()()
   819  
   820  	dr := testCwd(t)
   821  
   822  	opts := &GenOpts{
   823  		Spec:              filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"),
   824  		IncludeModel:      true,
   825  		IncludeHandler:    true,
   826  		IncludeParameters: true,
   827  		IncludeResponses:  true,
   828  		IncludeMain:       true,
   829  		ValidateSpec:      false,
   830  		APIPackage:        "restapi",
   831  		ModelPackage:      "model",
   832  		ServerPackage:     "server",
   833  		ClientPackage:     "client",
   834  		Target:            dr,
   835  		IsClient:          true,
   836  	}
   837  
   838  	// Testing Server Generation
   839  	require.NoError(t, opts.EnsureDefaults())
   840  
   841  	// minimal flattening
   842  	opts.FlattenOpts.Minimal = true
   843  	_, err := newAppGenerator("JsonRefOperation", nil, nil, opts)
   844  	// if flatten is not set, expand takes over so this would resume normally
   845  	assert.NoError(t, err)
   846  }
   847  
   848  func TestGenClientIssue890_ValidationFalseFlattenFalse(t *testing.T) {
   849  	defer discardOutput()()
   850  
   851  	dr := testCwd(t)
   852  	defer func() {
   853  		_ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi"))
   854  	}()
   855  
   856  	opts := testGenOpts()
   857  	opts.Spec = "../fixtures/bugs/890/swagger.yaml"
   858  	opts.ValidateSpec = false
   859  	// minimal flattening
   860  	opts.FlattenOpts.Minimal = true
   861  	// Testing this is enough as there is only one operation which is specified as $ref.
   862  	// If this doesn't get resolved then there will be an error definitely.
   863  	// New: Now if flatten is false, expand takes over so server generation should resume normally
   864  	assert.NoError(t, GenerateClient("foo", nil, nil, opts))
   865  }
   866  
   867  func TestGenServerIssue890_ValidationTrueFlattenFalse(t *testing.T) {
   868  	defer discardOutput()()
   869  
   870  	dr := testCwd(t)
   871  
   872  	opts := &GenOpts{
   873  		Spec:              filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"),
   874  		IncludeModel:      true,
   875  		IncludeHandler:    true,
   876  		IncludeParameters: true,
   877  		IncludeResponses:  true,
   878  		IncludeMain:       true,
   879  		ValidateSpec:      true,
   880  		APIPackage:        "restapi",
   881  		ModelPackage:      "model",
   882  		ServerPackage:     "server",
   883  		ClientPackage:     "client",
   884  		Target:            dr,
   885  		IsClient:          true,
   886  	}
   887  
   888  	// Testing Server Generation
   889  	require.NoError(t, opts.EnsureDefaults())
   890  
   891  	// minimal flattening
   892  	opts.FlattenOpts.Minimal = true
   893  
   894  	_, err := newAppGenerator("JsonRefOperation", nil, nil, opts)
   895  	// now if flatten is false, expand takes over so server generation should resume normally
   896  	assert.NoError(t, err)
   897  }
   898  
   899  func TestGenServerWithTemplate(t *testing.T) {
   900  	defer discardOutput()()
   901  
   902  	dr := testCwd(t)
   903  
   904  	tests := []struct {
   905  		name      string
   906  		opts      *GenOpts
   907  		wantError bool
   908  	}{
   909  		{
   910  			name: "None_existing_contributor_template",
   911  			opts: &GenOpts{
   912  				Spec:              filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"),
   913  				IncludeModel:      true,
   914  				IncludeHandler:    true,
   915  				IncludeParameters: true,
   916  				IncludeResponses:  true,
   917  				IncludeMain:       true,
   918  				ValidateSpec:      true,
   919  				APIPackage:        "restapi",
   920  				ModelPackage:      "model",
   921  				ServerPackage:     "server",
   922  				ClientPackage:     "client",
   923  				Target:            dr,
   924  				IsClient:          true,
   925  				Template:          "InvalidTemplate",
   926  			},
   927  			wantError: true,
   928  		},
   929  		{
   930  			name: "Existing_contributor",
   931  			opts: &GenOpts{
   932  				Spec:              filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"),
   933  				IncludeModel:      true,
   934  				IncludeHandler:    true,
   935  				IncludeParameters: true,
   936  				IncludeResponses:  true,
   937  				IncludeMain:       true,
   938  				ValidateSpec:      true,
   939  				APIPackage:        "restapi",
   940  				ModelPackage:      "model",
   941  				ServerPackage:     "server",
   942  				ClientPackage:     "client",
   943  				Target:            dr,
   944  				IsClient:          true,
   945  				Template:          "stratoscale",
   946  			},
   947  			wantError: false,
   948  		},
   949  	}
   950  
   951  	t.Run("codegen operations", func(t *testing.T) {
   952  		for _, toPin := range tests {
   953  			tt := toPin
   954  			t.Run(tt.name, func(t *testing.T) {
   955  				t.Parallel()
   956  
   957  				// Testing Server Generation
   958  				require.NoError(t, tt.opts.EnsureDefaults())
   959  
   960  				// minimal flattening
   961  				tt.opts.FlattenOpts.Minimal = true
   962  				_, err := newAppGenerator("JsonRefOperation", nil, nil, tt.opts)
   963  				if tt.wantError {
   964  					require.Error(t, err)
   965  				} else {
   966  					require.NoError(t, err)
   967  				}
   968  			})
   969  		}
   970  	})
   971  }
   972  
   973  func TestGenClientIssue890_ValidationTrueFlattenFalse(t *testing.T) {
   974  	defer discardOutput()()
   975  
   976  	dr := testCwd(t)
   977  	defer func() {
   978  		_ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi"))
   979  	}()
   980  
   981  	opts := testGenOpts()
   982  	opts.Spec = filepath.FromSlash("../fixtures/bugs/890/swagger.yaml")
   983  	opts.ValidateSpec = true
   984  	// Testing this is enough as there is only one operation which is specified as $ref.
   985  	// If this doesn't get resolved then there will be an error definitely.
   986  	// same here: now if flatten doesn't resume, expand takes over
   987  	assert.NoError(t, GenerateClient("foo", nil, nil, opts))
   988  }
   989  
   990  // This tests that securityDefinitions generate stable code
   991  func TestBuilder_Issue1214(t *testing.T) {
   992  	defer discardOutput()()
   993  
   994  	dr := testCwd(t)
   995  	const any = `(.|\n)+`
   996  
   997  	opts := &GenOpts{
   998  		Spec:              filepath.FromSlash("../fixtures/bugs/1214/fixture-1214.yaml"),
   999  		IncludeModel:      true,
  1000  		IncludeHandler:    true,
  1001  		IncludeParameters: true,
  1002  		IncludeResponses:  true,
  1003  		IncludeMain:       true,
  1004  		APIPackage:        "restapi",
  1005  		ModelPackage:      "model",
  1006  		ServerPackage:     "server",
  1007  		ClientPackage:     "client",
  1008  		Target:            dr,
  1009  		IsClient:          false,
  1010  	}
  1011  	require.NoError(t, opts.EnsureDefaults())
  1012  
  1013  	appGen, e := newAppGenerator("fixture-1214", nil, nil, opts)
  1014  	require.NoError(t, e)
  1015  
  1016  	op, e := appGen.makeCodegenApp()
  1017  	require.NoError(t, e)
  1018  
  1019  	for i := 0; i < 5; i++ {
  1020  		buf := bytes.NewBuffer(nil)
  1021  		err := templates.MustGet("serverConfigureapi").Execute(buf, op)
  1022  		require.NoError(t, err)
  1023  
  1024  		ff, err := appGen.GenOpts.LanguageOpts.FormatContent("fixture_1214_configure_api.go", buf.Bytes())
  1025  		require.NoErrorf(t, err, buf.String())
  1026  
  1027  		res := string(ff)
  1028  		assertRegexpInCode(t, any+
  1029  			`api\.AAuth = func\(user string, pass string\)`+any+
  1030  			`api\.BAuth = func\(token string\)`+any+
  1031  			`api\.CAuth = func\(token string\)`+any+
  1032  			`api\.DAuth = func\(token string\)`+any+
  1033  			`api\.EAuth = func\(token string, scopes \[\]string\)`+any, res)
  1034  
  1035  		buf = bytes.NewBuffer(nil)
  1036  		require.NoError(t, opts.templates.MustGet("serverBuilder").Execute(buf, op))
  1037  
  1038  		ff, err = appGen.GenOpts.LanguageOpts.FormatContent("fixture_1214_server.go", buf.Bytes())
  1039  		require.NoErrorf(t, err, buf.String())
  1040  
  1041  		res = string(ff)
  1042  		assertRegexpInCode(t, any+
  1043  			`AAuth: func\(user string, pass string\) \(interface{}, error\) {`+any+
  1044  			`BAuth: func\(token string\) \(interface{}, error\) {`+any+
  1045  			`CAuth: func\(token string\) \(interface{}, error\) {`+any+
  1046  			`DAuth: func\(token string\) \(interface{}, error\) {`+any+
  1047  			`EAuth: func\(token string, scopes \[\]string\) \(interface{}, error\) {`+any+
  1048  
  1049  			`AAuth func\(string, string\) \(interface{}, error\)`+any+
  1050  			`BAuth func\(string\) \(interface{}, error\)`+any+
  1051  			`CAuth func\(string\) \(interface{}, error\)`+any+
  1052  			`DAuth func\(string\) \(interface{}, error\)`+any+
  1053  			`EAuth func\(string, \[\]string\) \(interface{}, error\)`+any+
  1054  
  1055  			`if o\.AAuth == nil {`+any+
  1056  			`unregistered = append\(unregistered, "AAuth"\)`+any+
  1057  			`if o\.BAuth == nil {`+any+
  1058  			`unregistered = append\(unregistered, "K1Auth"\)`+any+
  1059  			`if o\.CAuth == nil {`+any+
  1060  			`unregistered = append\(unregistered, "K2Auth"\)`+any+
  1061  			`if o\.DAuth == nil {`+any+
  1062  			`unregistered = append\(unregistered, "K3Auth"\)`+any+
  1063  			`if o\.EAuth == nil {`+any+
  1064  			`unregistered = append\(unregistered, "EAuth"\)`+any+
  1065  
  1066  			`case "A":`+any+
  1067  			`case "B":`+any+
  1068  			`case "C":`+any+
  1069  			`case "D":`+any+
  1070  			`case "E":`+any, res)
  1071  	}
  1072  }
  1073  
  1074  func TestGenSecurityRequirements(t *testing.T) {
  1075  	for i := 0; i < 5; i++ {
  1076  		operation := "asecOp"
  1077  		b, err := opBuilder(operation, "../fixtures/bugs/1214/fixture-1214.yaml")
  1078  		require.NoError(t, err)
  1079  
  1080  		b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation)
  1081  		genRequirements := b.makeSecurityRequirements("o")
  1082  		assert.Len(t, genRequirements, 2)
  1083  		assert.Equal(t, []GenSecurityRequirements{
  1084  			{
  1085  				GenSecurityRequirement{
  1086  					Name:   "A",
  1087  					Scopes: []string{},
  1088  				},
  1089  				GenSecurityRequirement{
  1090  					Name:   "B",
  1091  					Scopes: []string{},
  1092  				},
  1093  				GenSecurityRequirement{
  1094  					Name:   "E",
  1095  					Scopes: []string{"s0", "s1", "s2", "s3", "s4"},
  1096  				},
  1097  			},
  1098  			{
  1099  				GenSecurityRequirement{
  1100  					Name:   "C",
  1101  					Scopes: []string{},
  1102  				},
  1103  				GenSecurityRequirement{
  1104  					Name:   "D",
  1105  					Scopes: []string{},
  1106  				},
  1107  				GenSecurityRequirement{
  1108  					Name:   "E",
  1109  					Scopes: []string{"s5", "s6", "s7", "s8", "s9"},
  1110  				},
  1111  			},
  1112  		}, genRequirements)
  1113  
  1114  		operation = "bsecOp"
  1115  		b, err = opBuilder(operation, "../fixtures/bugs/1214/fixture-1214.yaml")
  1116  		require.NoError(t, err)
  1117  
  1118  		b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation)
  1119  		genRequirements = b.makeSecurityRequirements("o")
  1120  		assert.Len(t, genRequirements, 2)
  1121  		assert.Equal(t, []GenSecurityRequirements{
  1122  			{
  1123  				GenSecurityRequirement{
  1124  					Name:   "A",
  1125  					Scopes: []string{},
  1126  				},
  1127  				GenSecurityRequirement{
  1128  					Name:   "E",
  1129  					Scopes: []string{"s0", "s1", "s2", "s3", "s4"},
  1130  				},
  1131  			},
  1132  			{
  1133  				GenSecurityRequirement{
  1134  					Name:   "D",
  1135  					Scopes: []string{},
  1136  				},
  1137  				GenSecurityRequirement{
  1138  					Name:   "E",
  1139  					Scopes: []string{"s5", "s6", "s7", "s8", "s9"},
  1140  				},
  1141  			},
  1142  		}, genRequirements)
  1143  	}
  1144  
  1145  	operation := "csecOp"
  1146  	b, err := opBuilder(operation, "../fixtures/bugs/1214/fixture-1214.yaml")
  1147  	require.NoError(t, err)
  1148  
  1149  	b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation)
  1150  	genRequirements := b.makeSecurityRequirements("o")
  1151  	assert.NotNil(t, genRequirements)
  1152  	assert.Len(t, genRequirements, 0)
  1153  
  1154  	operation = "nosecOp"
  1155  	b, err = opBuilder(operation, "../fixtures/bugs/1214/fixture-1214-2.yaml")
  1156  	require.NoError(t, err)
  1157  
  1158  	b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation)
  1159  	genRequirements = b.makeSecurityRequirements("o")
  1160  	assert.Nil(t, genRequirements)
  1161  }
  1162  
  1163  func TestGenerateServerOperation(t *testing.T) {
  1164  	defer discardOutput()()
  1165  
  1166  	fname := "../fixtures/codegen/todolist.simple.yml"
  1167  
  1168  	tgt, _ := ioutil.TempDir(filepath.Dir(fname), "generated")
  1169  	defer func() {
  1170  		_ = os.RemoveAll(tgt)
  1171  	}()
  1172  	o := &GenOpts{
  1173  		ValidateSpec:      false,
  1174  		IncludeModel:      true,
  1175  		IncludeHandler:    true,
  1176  		IncludeParameters: true,
  1177  		IncludeResponses:  true,
  1178  		ModelPackage:      "models",
  1179  		Spec:              fname,
  1180  		Target:            tgt,
  1181  	}
  1182  	require.NoError(t, o.EnsureDefaults())
  1183  
  1184  	require.Error(t, GenerateServerOperation([]string{"createTask"}, nil))
  1185  
  1186  	d := o.TemplateDir
  1187  	o.TemplateDir = "./nowhere"
  1188  	require.Error(t, GenerateServerOperation([]string{"notFound"}, o))
  1189  
  1190  	o.TemplateDir = d
  1191  	d = o.Spec
  1192  	o.Spec = "nowhere.yaml"
  1193  	require.Error(t, GenerateServerOperation([]string{"notFound"}, o))
  1194  
  1195  	o.Spec = d
  1196  	require.Error(t, GenerateServerOperation([]string{"notFound"}, o))
  1197  
  1198  	require.NoError(t, GenerateServerOperation([]string{"createTask"}, o))
  1199  
  1200  	// check expected files are generated and that's it
  1201  	_, err := os.Stat(filepath.Join(tgt, "tasks", "create_task.go"))
  1202  	assert.NoError(t, err)
  1203  	_, err = os.Stat(filepath.Join(tgt, "tasks", "create_task_parameters.go"))
  1204  	assert.NoError(t, err)
  1205  	_, err = os.Stat(filepath.Join(tgt, "tasks", "create_task_responses.go"))
  1206  	assert.NoError(t, err)
  1207  
  1208  	origStdout := os.Stdout
  1209  	defer func() {
  1210  		os.Stdout = origStdout
  1211  	}()
  1212  	os.Stdout, _ = os.Create(filepath.Join(tgt, "stdout"))
  1213  	o.DumpData = true
  1214  	// just checks this does not fail
  1215  	err = GenerateServerOperation([]string{"createTask"}, o)
  1216  	assert.NoError(t, err)
  1217  	_, err = os.Stat(filepath.Join(tgt, "stdout"))
  1218  	assert.NoError(t, err)
  1219  }
  1220  
  1221  // This tests that mimetypes generate stable code
  1222  func TestBuilder_Issue1646(t *testing.T) {
  1223  	defer discardOutput()()
  1224  
  1225  	dr := testCwd(t)
  1226  
  1227  	opts := &GenOpts{
  1228  		Spec:              filepath.FromSlash("../fixtures/bugs/1646/fixture-1646.yaml"),
  1229  		IncludeModel:      true,
  1230  		IncludeHandler:    true,
  1231  		IncludeParameters: true,
  1232  		IncludeResponses:  true,
  1233  		IncludeMain:       true,
  1234  		APIPackage:        "restapi",
  1235  		ModelPackage:      "model",
  1236  		ServerPackage:     "server",
  1237  		ClientPackage:     "client",
  1238  		Target:            dr,
  1239  		IsClient:          false,
  1240  	}
  1241  	err := opts.EnsureDefaults()
  1242  	require.NoError(t, err)
  1243  	appGen, err := newAppGenerator("fixture-1646", nil, nil, opts)
  1244  	require.NoError(t, err)
  1245  
  1246  	preCons, preConj := appGen.makeConsumes()
  1247  	preProds, preProdj := appGen.makeProduces()
  1248  	assert.True(t, preConj)
  1249  	assert.True(t, preProdj)
  1250  	for i := 0; i < 5; i++ {
  1251  		cons, conj := appGen.makeConsumes()
  1252  		prods, prodj := appGen.makeProduces()
  1253  		assert.True(t, conj)
  1254  		assert.True(t, prodj)
  1255  		assert.Equal(t, preConj, conj)
  1256  		assert.Equal(t, preProdj, prodj)
  1257  		assert.Equal(t, preCons, cons)
  1258  		assert.Equal(t, preProds, prods)
  1259  	}
  1260  }
  1261  
  1262  func TestGenServer_StrictAdditionalProperties(t *testing.T) {
  1263  	defer discardOutput()()
  1264  
  1265  	dr := testCwd(t)
  1266  
  1267  	opts := &GenOpts{
  1268  		Spec:              filepath.FromSlash("../fixtures/codegen/strict-additional-properties.yml"),
  1269  		IncludeModel:      true,
  1270  		IncludeHandler:    true,
  1271  		IncludeParameters: true,
  1272  		IncludeResponses:  true,
  1273  		IncludeMain:       true,
  1274  		APIPackage:        "restapi",
  1275  		ModelPackage:      "model",
  1276  		ServerPackage:     "server",
  1277  		ClientPackage:     "client",
  1278  		Target:            dr,
  1279  		IsClient:          false,
  1280  	}
  1281  	err := opts.EnsureDefaults()
  1282  	require.NoError(t, err)
  1283  
  1284  	opts.StrictAdditionalProperties = true
  1285  
  1286  	appGen, err := newAppGenerator("StrictAdditionalProperties", nil, nil, opts)
  1287  	require.NoError(t, err)
  1288  
  1289  	op, err := appGen.makeCodegenApp()
  1290  	require.NoError(t, err)
  1291  
  1292  	buf := bytes.NewBuffer(nil)
  1293  	err = templates.MustGet("serverOperation").Execute(buf, op.Operations[0])
  1294  	require.NoError(t, err)
  1295  
  1296  	ff, err := appGen.GenOpts.LanguageOpts.FormatContent("strictAdditionalProperties.go", buf.Bytes())
  1297  	require.NoErrorf(t, err, buf.String())
  1298  
  1299  	res := string(ff)
  1300  	for _, tt := range []struct {
  1301  		name      string
  1302  		assertion func(testing.TB, string, string) bool
  1303  	}{
  1304  		{"PostTestBody", assertInCode},
  1305  		{"PostTestParamsBodyExplicit", assertInCode},
  1306  		{"PostTestParamsBodyImplicit", assertInCode},
  1307  		{"PostTestParamsBodyDisabled", assertNotInCode},
  1308  	} {
  1309  		fn := funcBody(res, "*"+tt.name+") UnmarshalJSON(data []byte) error")
  1310  		require.NotEmpty(t, fn, "Method UnmarshalJSON should be defined for type *"+tt.name)
  1311  		tt.assertion(t, "dec.DisallowUnknownFields()", fn)
  1312  	}
  1313  }
  1314  
  1315  func makeClientTimeoutNameTest() []struct {
  1316  	seenIds  map[string]interface{}
  1317  	name     string
  1318  	expected string
  1319  } {
  1320  	return []struct {
  1321  		seenIds  map[string]interface{}
  1322  		name     string
  1323  		expected string
  1324  	}{
  1325  		{
  1326  			seenIds:  nil,
  1327  			name:     "witness",
  1328  			expected: "witness",
  1329  		},
  1330  		{
  1331  			seenIds: map[string]interface{}{
  1332  				"id": true,
  1333  			},
  1334  			name:     "timeout",
  1335  			expected: "timeout",
  1336  		},
  1337  		{
  1338  			seenIds: map[string]interface{}{
  1339  				"timeout":        true,
  1340  				"requesttimeout": true,
  1341  			},
  1342  			name:     "timeout",
  1343  			expected: "httpRequestTimeout",
  1344  		},
  1345  		{
  1346  			seenIds: map[string]interface{}{
  1347  				"timeout":            true,
  1348  				"requesttimeout":     true,
  1349  				"httprequesttimeout": true,
  1350  				"swaggertimeout":     true,
  1351  				"operationtimeout":   true,
  1352  				"optimeout":          true,
  1353  			},
  1354  			name:     "timeout",
  1355  			expected: "operTimeout",
  1356  		},
  1357  		{
  1358  			seenIds: map[string]interface{}{
  1359  				"timeout":            true,
  1360  				"requesttimeout":     true,
  1361  				"httprequesttimeout": true,
  1362  				"swaggertimeout":     true,
  1363  				"operationtimeout":   true,
  1364  				"optimeout":          true,
  1365  				"opertimeout":        true,
  1366  				"opertimeout1":       true,
  1367  			},
  1368  			name:     "timeout",
  1369  			expected: "operTimeout11",
  1370  		},
  1371  	}
  1372  }
  1373  
  1374  func TestRenameTimeout(t *testing.T) {
  1375  	for idx, toPin := range makeClientTimeoutNameTest() {
  1376  		i := idx
  1377  		testCase := toPin
  1378  		t.Run(testCase.name, func(t *testing.T) {
  1379  			t.Parallel()
  1380  			assert.Equalf(t, testCase.expected, renameTimeout(testCase.seenIds, testCase.name), "unexpected deconflicting value [%d]", i)
  1381  		})
  1382  	}
  1383  }
  1384  
  1385  func testInvalidParams() map[string]spec.Parameter {
  1386  	return map[string]spec.Parameter{
  1387  		"query#param1": *spec.QueryParam("param1"),
  1388  		"path#param1":  *spec.PathParam("param1"),
  1389  		"body#param1":  *spec.BodyParam("param1", &spec.Schema{}),
  1390  	}
  1391  }
  1392  
  1393  func TestParamMappings(t *testing.T) {
  1394  	// Test deconfliction of duplicate param names across param locations
  1395  	mappings, _ := paramMappings(testInvalidParams())
  1396  	require.Contains(t, mappings, "query")
  1397  	require.Contains(t, mappings, "path")
  1398  	require.Contains(t, mappings, "body")
  1399  	q := mappings["query"]
  1400  	p := mappings["path"]
  1401  	b := mappings["body"]
  1402  	require.Len(t, q, 1)
  1403  	require.Len(t, p, 1)
  1404  	require.Len(t, b, 1)
  1405  	require.Containsf(t, q, "param1", "unexpected content of %#v", q)
  1406  	require.Containsf(t, p, "param1", "unexpected content of %#v", p)
  1407  	require.Containsf(t, b, "param1", "unexpected content of %#v", b)
  1408  	assert.Equalf(t, "QueryParam1", q["param1"], "unexpected content of %#v", q["param1"])
  1409  	assert.Equalf(t, "PathParam1", p["param1"], "unexpected content of %#v", p["param1"])
  1410  	assert.Equalf(t, "BodyParam1", b["param1"], "unexpected content of %#v", b["param1"])
  1411  }
  1412  
  1413  func TestDeconflictTag(t *testing.T) {
  1414  	assert.Equal(t, "runtimeops", deconflictTag(nil, "runtime"))
  1415  	assert.Equal(t, "apiops", deconflictTag([]string{"tag1"}, "api"))
  1416  	assert.Equal(t, "apiops1", deconflictTag([]string{"tag1", "apiops"}, "api"))
  1417  	assert.Equal(t, "tlsops", deconflictTag([]string{"tag1"}, "tls"))
  1418  	assert.Equal(t, "mytag", deconflictTag([]string{"tag1", "apiops"}, "mytag"))
  1419  
  1420  	assert.Equal(t, "operationsops", renameOperationPackage([]string{"tag1"}, "operations"))
  1421  	assert.Equal(t, "operationsops11", renameOperationPackage([]string{"tag1", "operationsops1", "operationsops"}, "operations"))
  1422  }
  1423  
  1424  func TestGenServer_2161_panic(t *testing.T) {
  1425  	t.Parallel()
  1426  	defer discardOutput()()
  1427  
  1428  	generated, err := ioutil.TempDir(testCwd(t), "generated_2161")
  1429  	require.NoError(t, err)
  1430  
  1431  	defer func() {
  1432  		_ = os.RemoveAll(generated)
  1433  	}()
  1434  
  1435  	opts := &GenOpts{
  1436  		Spec:                       filepath.FromSlash("../fixtures/bugs/2161/fixture-2161-panic.json"),
  1437  		IncludeModel:               true,
  1438  		IncludeHandler:             true,
  1439  		IncludeParameters:          true,
  1440  		IncludeResponses:           true,
  1441  		IncludeMain:                true,
  1442  		APIPackage:                 "restapi",
  1443  		ModelPackage:               "model",
  1444  		ServerPackage:              "server",
  1445  		ClientPackage:              "client",
  1446  		Target:                     generated,
  1447  		IsClient:                   false,
  1448  		StrictAdditionalProperties: true,
  1449  	}
  1450  	require.NoError(t, opts.EnsureDefaults())
  1451  
  1452  	appGen, err := newAppGenerator("inlinedSubtype", nil, nil, opts)
  1453  	require.NoError(t, err)
  1454  
  1455  	op, err := appGen.makeCodegenApp()
  1456  	require.NoError(t, err)
  1457  
  1458  	buf := bytes.NewBuffer(nil)
  1459  	var selectedOp int
  1460  	for i := range op.Operations {
  1461  		if op.Operations[i].Name == "configuration_update_configuration_module" {
  1462  			selectedOp = i
  1463  		}
  1464  	}
  1465  	require.NotEmpty(t, selectedOp, "dev error: invalid test vs fixture")
  1466  
  1467  	require.NoError(t, opts.templates.MustGet("serverOperation").Execute(buf, op.Operations[selectedOp]))
  1468  
  1469  	_, err = appGen.GenOpts.LanguageOpts.FormatContent(op.Operations[selectedOp].Name+".go", buf.Bytes())
  1470  	require.NoErrorf(t, err, buf.String())
  1471  	// NOTE(fred): I know that the generated model is wrong from this spec at the moment.
  1472  	// The test with this fix simply asserts that there is no panic / internal error with building this.
  1473  }
  1474  
  1475  func TestGenServer_1659_Principal(t *testing.T) {
  1476  	defer discardOutput()()
  1477  
  1478  	dr := testCwd(t)
  1479  
  1480  	for _, toPin := range []struct {
  1481  		Title       string
  1482  		Opts        *GenOpts
  1483  		Expected    map[string][]string
  1484  		NotExpected map[string][]string
  1485  	}{
  1486  		{
  1487  			Title: "default",
  1488  			Opts: &GenOpts{
  1489  				Spec:              filepath.FromSlash("../fixtures/enhancements/1659/fixture-1659.yaml"),
  1490  				IncludeHandler:    true,
  1491  				IncludeParameters: true,
  1492  				IncludeResponses:  true,
  1493  				IncludeMain:       false,
  1494  				APIPackage:        "restapi",
  1495  				ModelPackage:      "models",
  1496  				ServerPackage:     "server",
  1497  				ClientPackage:     "client",
  1498  				Target:            dr,
  1499  				IsClient:          false,
  1500  			},
  1501  			Expected: map[string][]string{
  1502  				"configure": {
  1503  					`if api.ApikeyAuth == nil {`,
  1504  					`api.ApikeyAuth = func(token string) (interface{}, error) {`,
  1505  					`if api.BasicAuth == nil {`,
  1506  					`api.BasicAuth = func(user string, pass string) (interface{}, error) {`,
  1507  					`if api.PetstoreAuthAuth == nil {`,
  1508  					`api.PetstoreAuthAuth = func(token string, scopes []string) (interface{}, error) {`,
  1509  					`api.GetHandler =restapi.GetHandlerFunc(func(params restapi.GetParams, principal interface{}) middleware.Responder {`,
  1510  					`api.PostHandler =restapi.PostHandlerFunc(func(params restapi.PostParams) middleware.Responder {`,
  1511  				},
  1512  				"get": {
  1513  					`type GetHandlerFunc func(GetParams, interface{})  middleware.Responder`,
  1514  					`func (fn GetHandlerFunc) Handle(params GetParams, principal interface{})  middleware.Responder  {`,
  1515  					`return fn(params, principal)`,
  1516  					`type GetHandler interface {`,
  1517  					`Handle(GetParams, interface{})  middleware.Responder`,
  1518  					`uprinc, aCtx, err := o.Context.Authorize(r, route)`,
  1519  					`if uprinc != nil {`,
  1520  					`principal = uprinc.(interface{})`,
  1521  					`res := o.Handler.Handle(Params, principal)`,
  1522  				},
  1523  				"post": {
  1524  					`type PostHandlerFunc func(PostParams)  middleware.Responder`,
  1525  					`return fn(params)`,
  1526  					`type PostHandler interface {`,
  1527  					`Handle(PostParams)  middleware.Responder`,
  1528  					`res := o.Handler.Handle(Params)`,
  1529  				},
  1530  			},
  1531  			NotExpected: map[string][]string{
  1532  				"post": {
  1533  					`uprinc, aCtx, err := o.Context.Authorize(r, route)`,
  1534  					`principal = uprinc.(interface{})`,
  1535  				},
  1536  			},
  1537  		},
  1538  		{
  1539  			Title: "principal is struct",
  1540  			Opts: &GenOpts{
  1541  				Spec:              filepath.FromSlash("../fixtures/enhancements/1659/fixture-1659.yaml"),
  1542  				IncludeHandler:    true,
  1543  				IncludeParameters: true,
  1544  				IncludeResponses:  true,
  1545  				IncludeMain:       false,
  1546  				APIPackage:        "restapi",
  1547  				ModelPackage:      "models",
  1548  				ServerPackage:     "server",
  1549  				ClientPackage:     "client",
  1550  				Target:            dr,
  1551  				Principal:         "github.com/example/security.Principal",
  1552  				IsClient:          false,
  1553  			},
  1554  			Expected: map[string][]string{
  1555  				"configure": {
  1556  					`auth "github.com/example/security"`,
  1557  					`if api.ApikeyAuth == nil {`,
  1558  					`api.ApikeyAuth = func(token string) (*auth.Principal, error) {`,
  1559  					`if api.BasicAuth == nil {`,
  1560  					`api.BasicAuth = func(user string, pass string) (*auth.Principal, error) {`,
  1561  					`if api.PetstoreAuthAuth == nil {`,
  1562  					`api.PetstoreAuthAuth = func(token string, scopes []string) (*auth.Principal, error) {`,
  1563  					`api.GetHandler =restapi.GetHandlerFunc(func(params restapi.GetParams, principal *auth.Principal) middleware.Responder {`,
  1564  					`api.PostHandler =restapi.PostHandlerFunc(func(params restapi.PostParams) middleware.Responder {`,
  1565  				},
  1566  				"get": {
  1567  					`type GetHandlerFunc func(GetParams, *auth.Principal)  middleware.Responder`,
  1568  					`func (fn GetHandlerFunc) Handle(params GetParams, principal *auth.Principal)  middleware.Responder  {`,
  1569  					`return fn(params, principal)`,
  1570  					`type GetHandler interface {`,
  1571  					`Handle(GetParams, *auth.Principal)  middleware.Responder`,
  1572  					`uprinc, aCtx, err := o.Context.Authorize(r, route)`,
  1573  					`if uprinc != nil {`,
  1574  					`principal = uprinc.(*auth.Principal)`,
  1575  					`res := o.Handler.Handle(Params, principal)`,
  1576  				},
  1577  				"post": {
  1578  					`type PostHandlerFunc func(PostParams)  middleware.Responder`,
  1579  					`return fn(params)`,
  1580  					`type PostHandler interface {`,
  1581  					`Handle(PostParams)  middleware.Responder`,
  1582  					`res := o.Handler.Handle(Params)`,
  1583  				},
  1584  			},
  1585  			NotExpected: map[string][]string{
  1586  				"post": {
  1587  					`uprinc, aCtx, err := o.Context.Authorize(r, route)`,
  1588  					`principal = uprinc.(`,
  1589  				},
  1590  			},
  1591  		},
  1592  		{
  1593  			Title: "principal is interface",
  1594  			Opts: &GenOpts{
  1595  				Spec:                 filepath.FromSlash("../fixtures/enhancements/1659/fixture-1659.yaml"),
  1596  				IncludeHandler:       true,
  1597  				IncludeParameters:    true,
  1598  				IncludeResponses:     true,
  1599  				IncludeMain:          false,
  1600  				APIPackage:           "restapi",
  1601  				ModelPackage:         "models",
  1602  				ServerPackage:        "server",
  1603  				ClientPackage:        "client",
  1604  				Target:               dr,
  1605  				Principal:            "github.com/example/security.PrincipalIface",
  1606  				IsClient:             false,
  1607  				PrincipalCustomIface: true,
  1608  			},
  1609  			Expected: map[string][]string{
  1610  				"configure": {
  1611  					`auth "github.com/example/security"`,
  1612  					`if api.ApikeyAuth == nil {`,
  1613  					`api.ApikeyAuth = func(token string) (auth.PrincipalIface, error) {`,
  1614  					`if api.BasicAuth == nil {`,
  1615  					`api.BasicAuth = func(user string, pass string) (auth.PrincipalIface, error) {`,
  1616  					`if api.PetstoreAuthAuth == nil {`,
  1617  					`api.PetstoreAuthAuth = func(token string, scopes []string) (auth.PrincipalIface, error) {`,
  1618  					`api.GetHandler =restapi.GetHandlerFunc(func(params restapi.GetParams, principal auth.PrincipalIface) middleware.Responder {`,
  1619  					`api.PostHandler =restapi.PostHandlerFunc(func(params restapi.PostParams) middleware.Responder {`,
  1620  				},
  1621  				"get": {
  1622  					`type GetHandlerFunc func(GetParams, auth.PrincipalIface)  middleware.Responder`,
  1623  					`func (fn GetHandlerFunc) Handle(params GetParams, principal auth.PrincipalIface)  middleware.Responder  {`,
  1624  					`return fn(params, principal)`,
  1625  					`type GetHandler interface {`,
  1626  					`Handle(GetParams, auth.PrincipalIface)  middleware.Responder`,
  1627  					`uprinc, aCtx, err := o.Context.Authorize(r, route)`,
  1628  					`if uprinc != nil {`,
  1629  					`principal = uprinc.(auth.PrincipalIface)`,
  1630  					`res := o.Handler.Handle(Params, principal)`,
  1631  				},
  1632  				"post": {
  1633  					`type PostHandlerFunc func(PostParams)  middleware.Responder`,
  1634  					`return fn(params)`,
  1635  					`type PostHandler interface {`,
  1636  					`Handle(PostParams)  middleware.Responder`,
  1637  					`res := o.Handler.Handle(Params)`,
  1638  				},
  1639  			},
  1640  			NotExpected: map[string][]string{
  1641  				"post": {
  1642  					`uprinc, aCtx, err := o.Context.Authorize(r, route)`,
  1643  					`principal = uprinc.(`,
  1644  				},
  1645  			},
  1646  		},
  1647  		{
  1648  			Title: "stratoscale: principal is struct",
  1649  			Opts: &GenOpts{
  1650  				Spec:              filepath.FromSlash("../fixtures/enhancements/1659/fixture-1659.yaml"),
  1651  				IncludeHandler:    true,
  1652  				IncludeParameters: true,
  1653  				IncludeResponses:  true,
  1654  				IncludeMain:       false,
  1655  				APIPackage:        "restapi",
  1656  				ModelPackage:      "models",
  1657  				ServerPackage:     "server",
  1658  				ClientPackage:     "client",
  1659  				Target:            dr,
  1660  				Principal:         "github.com/example/security.Principal",
  1661  				IsClient:          false,
  1662  				Template:          "stratoscale",
  1663  			},
  1664  			Expected: map[string][]string{
  1665  				"configure": {
  1666  					`auth "github.com/example/security"`,
  1667  					`AuthApikey func(token string) (*auth.Principal, error)`,
  1668  					`AuthBasic func(user string, pass string) (*auth.Principal, error)`,
  1669  					`AuthPetstoreAuth func(token string, scopes []string) (*auth.Principal, error)`,
  1670  					`api.ApikeyAuth = func(token string) (*auth.Principal, error) {`,
  1671  					`if c.AuthApikey == nil {`,
  1672  					`panic("you specified a custom principal type, but did not provide the authenticator to provide this")`,
  1673  					`return c.AuthApikey(token)`,
  1674  					`api.BasicAuth = func(user string, pass string) (*auth.Principal, error) {`,
  1675  					`if c.AuthBasic == nil {`,
  1676  					`panic("you specified a custom principal type, but did not provide the authenticator to provide this")`,
  1677  					`return c.AuthBasic(user, pass)`,
  1678  					`api.PetstoreAuthAuth = func(token string, scopes []string) (*auth.Principal, error) {`,
  1679  					`if c.AuthPetstoreAuth == nil {`,
  1680  					`panic("you specified a custom principal type, but did not provide the authenticator to provide this")`,
  1681  					`return c.AuthPetstoreAuth(token, scopes)`,
  1682  					`api.APIAuthorizer = authorizer(c.Authorizer)`,
  1683  					`api.GetHandler =restapi.GetHandlerFunc(func(params restapi.GetParams, principal *auth.Principal) middleware.Responder {`,
  1684  					`ctx = storeAuth(ctx, principal)`,
  1685  					`return c.RestapiAPI.Get(ctx, params)`,
  1686  					`api.PostHandler =restapi.PostHandlerFunc(func(params restapi.PostParams) middleware.Responder {`,
  1687  					`return c.RestapiAPI.Post(ctx, params)`,
  1688  					`func (a authorizer) Authorize(req *http.Request, principal interface{}) error {`,
  1689  					`ctx := storeAuth(req.Context(), principal)`,
  1690  					`func storeAuth(ctx context.Context, principal interface{})`,
  1691  				},
  1692  			},
  1693  		},
  1694  		{
  1695  			Title: "stratoscale: principal is interface",
  1696  			Opts: &GenOpts{
  1697  				Spec:                 filepath.FromSlash("../fixtures/enhancements/1659/fixture-1659.yaml"),
  1698  				IncludeHandler:       true,
  1699  				IncludeParameters:    true,
  1700  				IncludeResponses:     true,
  1701  				IncludeMain:          false,
  1702  				APIPackage:           "restapi",
  1703  				ModelPackage:         "models",
  1704  				ServerPackage:        "server",
  1705  				ClientPackage:        "client",
  1706  				Target:               dr,
  1707  				Principal:            "github.com/example/security.PrincipalIface",
  1708  				IsClient:             false,
  1709  				PrincipalCustomIface: true,
  1710  				Template:             "stratoscale",
  1711  			},
  1712  			Expected: map[string][]string{
  1713  				"configure": {
  1714  					`auth "github.com/example/security"`,
  1715  					`AuthApikey func(token string) (auth.PrincipalIface, error)`,
  1716  					`AuthBasic func(user string, pass string) (auth.PrincipalIface, error)`,
  1717  					`AuthPetstoreAuth func(token string, scopes []string) (auth.PrincipalIface, error)`,
  1718  					`api.ApikeyAuth = func(token string) (auth.PrincipalIface, error) {`,
  1719  					`if c.AuthApikey == nil {`,
  1720  					`panic("you specified a custom principal type, but did not provide the authenticator to provide this")`,
  1721  					`return c.AuthApikey(token)`,
  1722  					`api.BasicAuth = func(user string, pass string) (auth.PrincipalIface, error) {`,
  1723  					`if c.AuthBasic == nil {`,
  1724  					`panic("you specified a custom principal type, but did not provide the authenticator to provide this")`,
  1725  					`return c.AuthBasic(user, pass)`,
  1726  					`api.PetstoreAuthAuth = func(token string, scopes []string) (auth.PrincipalIface, error) {`,
  1727  					`if c.AuthPetstoreAuth == nil {`,
  1728  					`panic("you specified a custom principal type, but did not provide the authenticator to provide this")`,
  1729  					`return c.AuthPetstoreAuth(token, scopes)`,
  1730  					`api.APIAuthorizer = authorizer(c.Authorizer)`,
  1731  					`api.GetHandler =restapi.GetHandlerFunc(func(params restapi.GetParams, principal auth.PrincipalIface) middleware.Responder {`,
  1732  					`ctx = storeAuth(ctx, principal)`,
  1733  					`return c.RestapiAPI.Get(ctx, params)`,
  1734  					`api.PostHandler =restapi.PostHandlerFunc(func(params restapi.PostParams) middleware.Responder {`,
  1735  					`return c.RestapiAPI.Post(ctx, params)`,
  1736  					`func (a authorizer) Authorize(req *http.Request, principal interface{}) error {`,
  1737  					`ctx := storeAuth(req.Context(), principal)`,
  1738  					`func storeAuth(ctx context.Context, principal interface{})`,
  1739  				},
  1740  			},
  1741  		},
  1742  	} {
  1743  		fixture := toPin
  1744  		t.Run(fixture.Title, func(t *testing.T) {
  1745  			t.Parallel()
  1746  
  1747  			opts := fixture.Opts
  1748  			require.NoError(t, opts.EnsureDefaults())
  1749  			require.NoError(t, opts.setTemplates())
  1750  
  1751  			appGen, err := newAppGenerator(fixture.Title, nil, nil, opts)
  1752  			require.NoError(t, err)
  1753  
  1754  			op, err := appGen.makeCodegenApp()
  1755  			require.NoError(t, err)
  1756  
  1757  			bufC := bytes.NewBuffer(nil)
  1758  			require.NoError(t, opts.templates.MustGet("serverConfigureapi").Execute(bufC, op))
  1759  
  1760  			_, err = appGen.GenOpts.LanguageOpts.FormatContent("configure_api.go", bufC.Bytes())
  1761  			require.NoErrorf(t, err, bufC.String())
  1762  
  1763  			for _, line := range fixture.Expected["configure"] {
  1764  				assertInCode(t, line, bufC.String())
  1765  			}
  1766  			for _, line := range fixture.NotExpected["configure"] {
  1767  				assertNotInCode(t, line, bufC.String())
  1768  			}
  1769  
  1770  			for i := range op.Operations {
  1771  				bufO := bytes.NewBuffer(nil)
  1772  				require.NoError(t, opts.templates.MustGet("serverOperation").Execute(bufO, op.Operations[i]))
  1773  
  1774  				_, erf := appGen.GenOpts.LanguageOpts.FormatContent(op.Operations[i].Name+".go", bufO.Bytes())
  1775  				require.NoErrorf(t, erf, bufO.String())
  1776  
  1777  				for _, line := range fixture.Expected[op.Operations[i].Name] {
  1778  					assertInCode(t, line, bufO.String())
  1779  				}
  1780  				for _, line := range fixture.NotExpected[op.Operations[i].Name] {
  1781  					assertNotInCode(t, line, bufO.String())
  1782  				}
  1783  			}
  1784  		})
  1785  	}
  1786  }