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