github.com/ffalor/go-swagger@v0.0.0-20231011000038-9f25265ac351/generator/discriminators_test.go (about)

     1  package generator
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/go-openapi/analysis"
     8  	"github.com/go-openapi/loads"
     9  	"github.com/go-openapi/swag"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestBuildDiscriminatorMap(t *testing.T) {
    15  	specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
    16  	require.NoError(t, err)
    17  
    18  	di := discriminatorInfo(analysis.New(specDoc.Spec()))
    19  	assert.Len(t, di.Discriminators, 1)
    20  	assert.Len(t, di.Discriminators["#/definitions/Pet"].Children, 2)
    21  	assert.Len(t, di.Discriminated, 2)
    22  }
    23  
    24  func TestGenerateModel_DiscriminatorSlices(t *testing.T) {
    25  	specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
    26  	require.NoError(t, err)
    27  
    28  	definitions := specDoc.Spec().Definitions
    29  	k := "Kennel"
    30  	schema := definitions[k]
    31  	opts := opts()
    32  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
    33  	require.NoError(t, err)
    34  	assert.True(t, genModel.HasBaseType)
    35  
    36  	buf := bytes.NewBuffer(nil)
    37  	err = opts.templates.MustGet("model").Execute(buf, genModel)
    38  	require.NoError(t, err)
    39  
    40  	b, err := opts.LanguageOpts.FormatContent("has_discriminator.go", buf.Bytes())
    41  	require.NoErrorf(t, err, buf.String())
    42  
    43  	res := string(b)
    44  	assertInCode(t, "type Kennel struct {", res)
    45  	assertInCode(t, "ID int64 `json:\"id,omitempty\"`", res)
    46  	assertInCode(t, "Pets []Pet `json:\"pets\"`", res)
    47  	assertInCode(t, "if err := m.petsField[i].Validate(formats); err != nil {", res)
    48  	assertInCode(t, "m.validatePet", res)
    49  }
    50  
    51  func TestGenerateModel_Discriminators(t *testing.T) {
    52  	specDoc, e := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
    53  	require.NoError(t, e)
    54  
    55  	definitions := specDoc.Spec().Definitions
    56  
    57  	for _, k := range []string{"cat", "Dog"} {
    58  		schema := definitions[k]
    59  		opts := opts()
    60  		genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
    61  		require.NoError(t, err)
    62  
    63  		assert.True(t, genModel.IsComplexObject)
    64  		assert.Equal(t, "petType", genModel.DiscriminatorField)
    65  		assert.Equal(t, k, genModel.DiscriminatorValue)
    66  
    67  		buf := bytes.NewBuffer(nil)
    68  		err = opts.templates.MustGet("model").Execute(buf, genModel)
    69  		require.NoError(t, err)
    70  
    71  		b, err := opts.LanguageOpts.FormatContent("discriminated.go", buf.Bytes())
    72  		require.NoErrorf(t, err, buf.String())
    73  
    74  		res := string(b)
    75  		assertNotInCode(t, "m.Pet.Validate", res)
    76  		assertInCode(t, "if err := m.validateName(formats); err != nil {", res)
    77  
    78  		if k == "Dog" {
    79  			assertInCode(t, "func (m *Dog) validatePackSize(formats strfmt.Registry) error {", res)
    80  			assertInCode(t, "if err := m.validatePackSize(formats); err != nil {", res)
    81  			assertInCode(t, "PackSize: m.PackSize,", res)
    82  			assertInCode(t, "validate.Required(\"packSize\", \"body\", m.PackSize)", res)
    83  		} else {
    84  			assertInCode(t, "func (m *Cat) validateHuntingSkill(formats strfmt.Registry) error {", res)
    85  			assertInCode(t, "if err := m.validateHuntingSkill(formats); err != nil {", res)
    86  			assertInCode(t, "if err := m.validateHuntingSkillEnum(\"huntingSkill\", \"body\", *m.HuntingSkill); err != nil {", res)
    87  			assertInCode(t, "HuntingSkill: m.HuntingSkill", res)
    88  		}
    89  
    90  		assertInCode(t, "Name *string `json:\"name\"`", res)
    91  		assertInCode(t, "PetType string `json:\"petType\"`", res)
    92  
    93  		assertInCode(t, "result.nameField = base.Name", res)
    94  		assertInCode(t, "if base.PetType != result.PetType() {", res)
    95  		assertInCode(t, "return errors.New(422, \"invalid petType value: %q\", base.PetType)", res)
    96  
    97  		kk := swag.ToGoName(k)
    98  		assertInCode(t, "func (m *"+kk+") Name() *string", res)
    99  		assertInCode(t, "func (m *"+kk+") SetName(val *string)", res)
   100  		assertInCode(t, "func (m *"+kk+") PetType() string", res)
   101  		assertInCode(t, "func (m *"+kk+") SetPetType(val string)", res)
   102  		assertInCode(t, "validate.Required(\"name\", \"body\", m.Name())", res)
   103  	}
   104  
   105  	k := "Pet"
   106  	schema := definitions[k]
   107  	opts := opts()
   108  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   109  	require.NoError(t, err)
   110  
   111  	assert.True(t, genModel.IsComplexObject)
   112  	assert.Equal(t, "petType", genModel.DiscriminatorField)
   113  	assert.Len(t, genModel.Discriminates, 3)
   114  	assert.Len(t, genModel.ExtraSchemas, 0)
   115  	assert.Equal(t, "Pet", genModel.Discriminates["Pet"])
   116  	assert.Equal(t, "Cat", genModel.Discriminates["cat"])
   117  	assert.Equal(t, "Dog", genModel.Discriminates["Dog"])
   118  
   119  	buf := bytes.NewBuffer(nil)
   120  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   121  	require.NoError(t, err)
   122  
   123  	b, err := opts.LanguageOpts.FormatContent("with_discriminator.go", buf.Bytes())
   124  	require.NoErrorf(t, err, buf.String())
   125  
   126  	res := string(b)
   127  	assertInCode(t, "type Pet interface {", res)
   128  	assertInCode(t, "runtime.Validatable", res)
   129  	assertInCode(t, "Name() *string", res)
   130  	assertInCode(t, "SetName(*string)", res)
   131  	assertInCode(t, "PetType() string", res)
   132  	assertInCode(t, "SetPetType(string)", res)
   133  	assertInCode(t, "type pet struct {", res)
   134  	assertInCode(t, "UnmarshalPet(reader io.Reader, consumer runtime.Consumer) (Pet, error)", res)
   135  	assertInCode(t, "PetType string `json:\"petType\"`", res)
   136  	assertInCode(t, "validate.RequiredString(\"petType\"", res)
   137  	assertInCode(t, "switch getType.PetType {", res)
   138  	assertInCode(t, "var result pet", res)
   139  	assertInCode(t, "var result Cat", res)
   140  	assertInCode(t, "var result Dog", res)
   141  }
   142  
   143  func TestGenerateModel_UsesDiscriminator(t *testing.T) {
   144  	specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
   145  	require.NoError(t, err)
   146  
   147  	definitions := specDoc.Spec().Definitions
   148  	k := "WithPet"
   149  	schema := definitions[k]
   150  	opts := opts()
   151  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   152  	require.NoError(t, err)
   153  
   154  	require.True(t, genModel.HasBaseType)
   155  
   156  	buf := bytes.NewBuffer(nil)
   157  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   158  	require.NoError(t, err)
   159  
   160  	b, err := opts.LanguageOpts.FormatContent("has_discriminator.go", buf.Bytes())
   161  	require.NoErrorf(t, err, buf.String())
   162  	res := string(b)
   163  	assertInCode(t, "type WithPet struct {", res)
   164  	assertInCode(t, "ID int64 `json:\"id,omitempty\"`", res)
   165  	assertInCode(t, "petField Pet", res)
   166  	assertInCode(t, "if err := m.Pet().Validate(formats); err != nil {", res)
   167  	assertInCode(t, "m.validatePet", res)
   168  }
   169  
   170  func TestGenerateClient_OKResponseWithDiscriminator(t *testing.T) {
   171  	specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
   172  	require.NoError(t, err)
   173  
   174  	method, path, op, ok := analysis.New(specDoc.Spec()).OperationForName("modelOp")
   175  	require.True(t, ok)
   176  
   177  	opts := opts()
   178  	bldr := codeGenOpBuilder{
   179  		Name:          "modelOp",
   180  		Method:        method,
   181  		Path:          path,
   182  		APIPackage:    "restapi",
   183  		ModelsPackage: "models",
   184  		Principal:     "",
   185  		Target:        ".",
   186  		Doc:           specDoc,
   187  		Analyzed:      analysis.New(specDoc.Spec()),
   188  		Operation:     *op,
   189  		Authed:        false,
   190  		DefaultScheme: "http",
   191  		ExtraSchemas:  make(map[string]GenSchema),
   192  		GenOpts:       opts,
   193  	}
   194  
   195  	genOp, err := bldr.MakeOperation()
   196  	require.NoError(t, err)
   197  
   198  	assert.True(t, genOp.Responses[0].Schema.IsBaseType)
   199  	var buf bytes.Buffer
   200  	err = opts.templates.MustGet("clientResponse").Execute(&buf, genOp)
   201  	require.NoError(t, err)
   202  
   203  	res := buf.String()
   204  	assertInCode(t, "Payload models.Pet", res)
   205  	assertInCode(t, "o.Payload = payload", res)
   206  	assertInCode(t, "payload, err := models.UnmarshalPet(response.Body(), consumer)", res)
   207  }
   208  
   209  func TestGenerateServer_Parameters(t *testing.T) {
   210  	specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml")
   211  	require.NoError(t, err)
   212  
   213  	method, path, op, ok := analysis.New(specDoc.Spec()).OperationForName("modelOp")
   214  	require.True(t, ok)
   215  
   216  	opts := opts()
   217  	bldr := codeGenOpBuilder{
   218  		Name:          "modelOp",
   219  		Method:        method,
   220  		Path:          path,
   221  		APIPackage:    "restapi",
   222  		ModelsPackage: "models",
   223  		Principal:     "",
   224  		Target:        ".",
   225  		Doc:           specDoc,
   226  		Analyzed:      analysis.New(specDoc.Spec()),
   227  		Operation:     *op,
   228  		Authed:        false,
   229  		DefaultScheme: "http",
   230  		ExtraSchemas:  make(map[string]GenSchema),
   231  		GenOpts:       opts,
   232  	}
   233  	genOp, err := bldr.MakeOperation()
   234  	require.NoError(t, err)
   235  
   236  	assert.True(t, genOp.Responses[0].Schema.IsBaseType)
   237  	var buf bytes.Buffer
   238  	err = opts.templates.MustGet("serverParameter").Execute(&buf, genOp)
   239  	require.NoErrorf(t, err, buf.String())
   240  
   241  	res := buf.String()
   242  	assertInCode(t, "Pet models.Pet", res)
   243  	assertInCode(t, "body, err := models.UnmarshalPet(r.Body, route.Consumer)", res)
   244  	assertInCode(t, "o.Pet = body", res)
   245  }
   246  
   247  func TestGenerateModel_Discriminator_Billforward(t *testing.T) {
   248  	specDoc, err := loads.Spec("../fixtures/codegen/billforward.discriminators.yml")
   249  	require.NoError(t, err)
   250  
   251  	definitions := specDoc.Spec().Definitions
   252  	k := "FlatPricingComponent"
   253  	schema := definitions[k]
   254  	opts := opts()
   255  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   256  	require.NoError(t, err)
   257  	require.True(t, genModel.IsSubType)
   258  
   259  	buf := bytes.NewBuffer(nil)
   260  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   261  	require.NoError(t, err)
   262  
   263  	b, err := opts.LanguageOpts.FormatContent("has_discriminator.go", buf.Bytes())
   264  	require.NoErrorf(t, err, buf.String())
   265  
   266  	res := string(b)
   267  	assertNotInCode(t, "for i := 0; i < len(m.PriceExplanation()); i++", res)
   268  }
   269  
   270  func TestGenerateModel_Bitbucket_Repository(t *testing.T) {
   271  	specDoc, err := loads.Spec("../fixtures/codegen/bitbucket.json")
   272  	require.NoError(t, err)
   273  
   274  	definitions := specDoc.Spec().Definitions
   275  	k := "repository"
   276  	schema := definitions[k]
   277  	opts := opts()
   278  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   279  	require.NoError(t, err)
   280  
   281  	assert.True(t, genModel.IsNullable)
   282  	for _, gm := range genModel.AllOf {
   283  		for _, p := range gm.Properties {
   284  			if p.Name == "parent" {
   285  				assert.True(t, p.IsNullable)
   286  			}
   287  		}
   288  	}
   289  
   290  	buf := bytes.NewBuffer(nil)
   291  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   292  	require.NoError(t, err)
   293  
   294  	b, err := opts.LanguageOpts.FormatContent("repository.go", buf.Bytes())
   295  	require.NoErrorf(t, err, buf.String())
   296  
   297  	res := string(b)
   298  	assertInCode(t, "Parent *Repository", res)
   299  	assertNotInCode(t, "Parent Repository", res)
   300  }
   301  
   302  func TestGenerateModel_Bitbucket_WebhookSubscription(t *testing.T) {
   303  	specDoc, err := loads.Spec("../fixtures/codegen/bitbucket.json")
   304  	require.NoError(t, err)
   305  
   306  	definitions := specDoc.Spec().Definitions
   307  	k := "webhook_subscription"
   308  	schema := definitions[k]
   309  	opts := opts()
   310  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   311  	require.NoError(t, err)
   312  
   313  	buf := bytes.NewBuffer(nil)
   314  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   315  	require.NoError(t, err)
   316  
   317  	b, err := opts.LanguageOpts.FormatContent("webhook_subscription.go", buf.Bytes())
   318  	require.NoErrorf(t, err, buf.String())
   319  
   320  	res := string(b)
   321  	assertInCode(t, "result.subjectField", res)
   322  	assertInCode(t, "Subject: m.Subject()", res)
   323  }
   324  
   325  func TestGenerateModel_Issue319(t *testing.T) {
   326  	specDoc, err := loads.Spec("../fixtures/bugs/319/swagger.yml")
   327  	require.NoError(t, err)
   328  
   329  	definitions := specDoc.Spec().Definitions
   330  	k := "Container"
   331  	schema := definitions[k]
   332  	opts := opts()
   333  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   334  	require.NoError(t, err)
   335  	require.Equal(t, "map[string]Base", genModel.Properties[0].GoType)
   336  
   337  	buf := bytes.NewBuffer(nil)
   338  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   339  	require.NoError(t, err)
   340  
   341  	b, err := opts.LanguageOpts.FormatContent("ifacedmap.go", buf.Bytes())
   342  	require.NoErrorf(t, err, buf.String())
   343  
   344  	res := string(b)
   345  	assertInCode(t, "MapNoWorky map[string]Base", res)
   346  }
   347  
   348  func TestGenerateModel_Issue541(t *testing.T) {
   349  	specDoc, err := loads.Spec("../fixtures/bugs/541/swagger.json")
   350  	require.NoError(t, err)
   351  
   352  	definitions := specDoc.Spec().Definitions
   353  	k := "Lion"
   354  	schema := definitions[k]
   355  	opts := opts()
   356  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   357  	require.NoError(t, err)
   358  	require.NotEmpty(t, genModel.AllOf)
   359  
   360  	buf := bytes.NewBuffer(nil)
   361  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   362  	require.NoError(t, err)
   363  
   364  	b, err := opts.LanguageOpts.FormatContent("lion.go", buf.Bytes())
   365  	require.NoErrorf(t, err, buf.String())
   366  
   367  	res := string(b)
   368  	assertInCode(t, "Cat", res)
   369  	assertInCode(t, "m.Cat.Validate(formats)", res)
   370  }
   371  
   372  func TestGenerateModel_Issue436(t *testing.T) {
   373  	specDoc, err := loads.Spec("../fixtures/bugs/436/swagger.yml")
   374  	require.NoError(t, err)
   375  
   376  	definitions := specDoc.Spec().Definitions
   377  	k := "Image"
   378  	schema := definitions[k]
   379  	opts := opts()
   380  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   381  	require.NoError(t, err)
   382  	require.NotEmpty(t, genModel.AllOf)
   383  
   384  	buf := bytes.NewBuffer(nil)
   385  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   386  	require.NoError(t, err)
   387  
   388  	b, err := opts.LanguageOpts.FormatContent("lion.go", buf.Bytes())
   389  	require.NoErrorf(t, err, buf.String())
   390  
   391  	res := string(b)
   392  	assertInCode(t, "Links", res)
   393  	assertInCode(t, "m.Links.Validate(formats)", res)
   394  	assertInCode(t, "Created *strfmt.DateTime `json:\"created\"`", res)
   395  	assertInCode(t, "ImageID *string `json:\"imageId\"`", res)
   396  	assertInCode(t, "Size *int64 `json:\"size\"`", res)
   397  }
   398  
   399  func TestGenerateModel_Issue740(t *testing.T) {
   400  	specDoc, err := loads.Spec("../fixtures/bugs/740/swagger.yml")
   401  	require.NoError(t, err)
   402  
   403  	definitions := specDoc.Spec().Definitions
   404  	k := "Bar"
   405  	schema := definitions[k]
   406  	opts := opts()
   407  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   408  	require.NoError(t, err)
   409  	require.NotEmpty(t, genModel.AllOf)
   410  
   411  	buf := bytes.NewBuffer(nil)
   412  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   413  	require.NoError(t, err)
   414  
   415  	b, err := opts.LanguageOpts.FormatContent("bar.go", buf.Bytes())
   416  	require.NoErrorf(t, err, buf.String())
   417  
   418  	res := string(b)
   419  	assertInCode(t, "Foo", res)
   420  	assertInCode(t, "m.Foo.Validate(formats)", res)
   421  }
   422  
   423  func TestGenerateModel_Issue743(t *testing.T) {
   424  	specDoc, err := loads.Spec("../fixtures/bugs/743/swagger.yml")
   425  	require.NoError(t, err)
   426  
   427  	definitions := specDoc.Spec().Definitions
   428  	k := "Awol"
   429  	schema := definitions[k]
   430  	opts := opts()
   431  	genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts)
   432  	require.NoError(t, err)
   433  	require.NotEmpty(t, genModel.AllOf)
   434  
   435  	buf := bytes.NewBuffer(nil)
   436  	err = opts.templates.MustGet("model").Execute(buf, genModel)
   437  	require.NoError(t, err)
   438  
   439  	b, err := opts.LanguageOpts.FormatContent("awol.go", buf.Bytes())
   440  	require.NoErrorf(t, err, buf.String())
   441  
   442  	res := string(b)
   443  	assertInCode(t, "Foo", res)
   444  	assertInCode(t, "Bar", res)
   445  	assertInCode(t, "m.Foo.Validate(formats)", res)
   446  	assertInCode(t, "m.Bar.Validate(formats)", res)
   447  	assertInCode(t, "swag.WriteJSON(m.Foo)", res)
   448  	assertInCode(t, "swag.WriteJSON(m.Bar)", res)
   449  	assertInCode(t, "swag.ReadJSON(raw, &aO0)", res)
   450  	assertInCode(t, "swag.ReadJSON(raw, &aO1)", res)
   451  	assertInCode(t, "m.Foo = aO0", res)
   452  	assertInCode(t, "m.Bar = aO1", res)
   453  }