github.com/thetreep/go-swagger@v0.0.0-20240223100711-35af64f14f01/generator/model_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 "fmt" 20 "os" 21 "path/filepath" 22 "regexp" 23 "strconv" 24 "strings" 25 "testing" 26 "text/template" 27 28 "github.com/go-openapi/loads" 29 "github.com/go-openapi/swag" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 ) 33 34 type templateTest struct { 35 t testing.TB 36 template *template.Template 37 } 38 39 func (tt *templateTest) assertRender(data interface{}, expected string) (success bool) { 40 buf := bytes.NewBuffer(nil) 41 defer func() { 42 success = !tt.t.Failed() 43 }() 44 45 require.NoError(tt.t, tt.template.Execute(buf, data)) 46 47 trimmed := strings.TrimLeft(buf.String(), "\n\t ") 48 exp := strings.TrimLeft(expected, "\n\t ") 49 assert.Equal(tt.t, exp, trimmed) 50 51 return 52 } 53 54 func TestGenerateModel_Sanity(t *testing.T) { 55 t.Parallel() 56 57 // just checks if it can render and format these things 58 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 59 require.NoError(t, err) 60 61 definitions := specDoc.Spec().Definitions 62 63 t.Run("mode sanity check", func(t *testing.T) { 64 for k, schema := range definitions { 65 opts := opts() 66 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 67 require.NoError(t, err) 68 69 rendered := bytes.NewBuffer(nil) 70 71 require.NoErrorf(t, opts.templates.MustGet("model").Execute(rendered, genModel), 72 "Unexpected error while rendering models for fixtures/codegen/todolist.models.yml: %v", err) 73 74 _, err = opts.LanguageOpts.FormatContent(strings.ToLower(k)+".go", rendered.Bytes()) 75 require.NoError(t, err) 76 } 77 }) 78 } 79 80 func TestGenerateModel_DocString(t *testing.T) { 81 funcMap := FuncMapFunc(DefaultLanguageFunc()) 82 templ := template.Must(template.New("docstring").Funcs(funcMap).Parse(string(assets["docstring.gotmpl"]))) 83 tt := templateTest{t, templ} 84 85 var gmp GenSchema 86 gmp.Title = "The title of the property" 87 gmp.Description = "The description of the property" 88 expected := `The title of the property 89 // 90 // The description of the property` 91 tt.assertRender(gmp, expected) 92 93 gmp.Title = "" 94 expected = `The description of the property` 95 tt.assertRender(gmp, expected) 96 97 gmp.Description = "" 98 gmp.Name = "theModel" 99 expected = `the model` 100 tt.assertRender(gmp, expected) 101 } 102 103 func TestGenerateModel_PropertyValidation(t *testing.T) { 104 funcMap := FuncMapFunc(DefaultLanguageFunc()) 105 templ := template.Must(template.New("propertyValidationDocString").Funcs(funcMap).Parse(string(assets["validation/structfield.gotmpl"]))) 106 tt := templateTest{t, templ} 107 108 var gmp GenSchema 109 gmp.Required = true 110 tt.assertRender(gmp, ` 111 // Required: true`) 112 var fl float64 = 10 113 var in1 int64 = 20 114 var in2 int64 = 30 115 gmp.Maximum = &fl 116 gmp.ExclusiveMaximum = true 117 gmp.Minimum = &fl 118 gmp.ExclusiveMinimum = true 119 gmp.MaxLength = &in1 120 gmp.MinLength = &in1 121 gmp.Pattern = "\\w[\\w- ]+" 122 gmp.MaxItems = &in2 123 gmp.MinItems = &in2 124 gmp.UniqueItems = true 125 126 tt.assertRender(gmp, ` 127 // Required: true 128 // Maximum: < 10 129 // Minimum: > 10 130 // Max Length: 20 131 // Min Length: 20 132 // Pattern: \w[\w- ]+ 133 // Max Items: 30 134 // Min Items: 30 135 // Unique: true`) 136 137 gmp.Required = false 138 gmp.ExclusiveMaximum = false 139 gmp.ExclusiveMinimum = false 140 tt.assertRender(gmp, ` 141 // Maximum: 10 142 // Minimum: 10 143 // Max Length: 20 144 // Min Length: 20 145 // Pattern: \w[\w- ]+ 146 // Max Items: 30 147 // Min Items: 30 148 // Unique: true`) 149 } 150 151 func TestGenerateModel_SchemaField(t *testing.T) { 152 tt := templateTest{t, templates.MustGet("model").Lookup("structfield")} 153 154 var gmp GenSchema 155 gmp.Name = "some name" 156 gmp.OriginalName = "some name" 157 gmp.resolvedType = resolvedType{GoType: "string", IsPrimitive: true, IsEmptyOmitted: true} 158 gmp.Title = "The title of the property" 159 gmp.CustomTag = "mytag:\"foobar,foobaz\"" 160 161 tt.assertRender(&gmp, `// The title of the property 162 `+"SomeName string `json:\"some name,omitempty\" mytag:\"foobar,foobaz\"`\n") 163 164 var fl float64 = 10 165 var in1 int64 = 20 166 var in2 int64 = 30 167 168 gmp.Description = "The description of the property" 169 gmp.Required = true 170 gmp.Maximum = &fl 171 gmp.ExclusiveMaximum = true 172 gmp.Minimum = &fl 173 gmp.ExclusiveMinimum = true 174 gmp.MaxLength = &in1 175 gmp.MinLength = &in1 176 gmp.Pattern = "\\w[\\w- ]+" 177 gmp.MaxItems = &in2 178 gmp.MinItems = &in2 179 gmp.UniqueItems = true 180 gmp.ReadOnly = true 181 gmp.StructTags = []string{"json", "db", "example"} 182 gmp.Example = "some example\"" 183 tt.assertRender(&gmp, `// The title of the property 184 // 185 // The description of the property 186 // Example: some example" 187 // Required: true 188 // Read Only: true 189 // Maximum: < 10 190 // Minimum: > 10 191 // Max Length: 20 192 // Min Length: 20 193 // Pattern: \w[\w- ]+ 194 // Max Items: 30 195 // Min Items: 30 196 // Unique: true 197 `+"SomeName string `json:\"some name\" db:\"some name\" example:\"some example\\\"\" mytag:\"foobar,foobaz\"`\n") 198 199 gmp.Example = "some example``" 200 tt.assertRender(&gmp, `// The title of the property 201 // 202 // The description of the property 203 // Example: some example`+"``"+` 204 // Required: true 205 // Read Only: true 206 // Maximum: < 10 207 // Minimum: > 10 208 // Max Length: 20 209 // Min Length: 20 210 // Pattern: \w[\w- ]+ 211 // Max Items: 30 212 // Min Items: 30 213 // Unique: true 214 `+"SomeName string \"json:\\\"some name\\\" db:\\\"some name\\\" example:\\\"some example``\\\" mytag:\\\"foobar,foobaz\\\"\"\n") 215 } 216 217 var schTypeGenDataSimple = []struct { 218 Value GenSchema 219 Expected string 220 }{ 221 {GenSchema{resolvedType: resolvedType{GoType: "string", IsPrimitive: true}}, "string"}, 222 {GenSchema{resolvedType: resolvedType{GoType: "string", IsPrimitive: true, IsNullable: true}}, "*string"}, 223 {GenSchema{resolvedType: resolvedType{GoType: "bool", IsPrimitive: true}}, "bool"}, 224 {GenSchema{resolvedType: resolvedType{GoType: "int32", IsPrimitive: true}}, "int32"}, 225 {GenSchema{resolvedType: resolvedType{GoType: "int64", IsPrimitive: true}}, "int64"}, 226 {GenSchema{resolvedType: resolvedType{GoType: "float32", IsPrimitive: true}}, "float32"}, 227 {GenSchema{resolvedType: resolvedType{GoType: "float64", IsPrimitive: true}}, "float64"}, 228 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.Base64", IsPrimitive: true}}, "strfmt.Base64"}, 229 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.Date", IsPrimitive: true}}, "strfmt.Date"}, 230 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.DateTime", IsPrimitive: true}}, "strfmt.DateTime"}, 231 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.URI", IsPrimitive: true}}, "strfmt.URI"}, 232 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.Email", IsPrimitive: true}}, "strfmt.Email"}, 233 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.Hostname", IsPrimitive: true}}, "strfmt.Hostname"}, 234 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.IPv4", IsPrimitive: true}}, "strfmt.IPv4"}, 235 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.IPv6", IsPrimitive: true}}, "strfmt.IPv6"}, 236 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.UUID", IsPrimitive: true}}, "strfmt.UUID"}, 237 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.UUID3", IsPrimitive: true}}, "strfmt.UUID3"}, 238 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.UUID4", IsPrimitive: true}}, "strfmt.UUID4"}, 239 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.UUID5", IsPrimitive: true}}, "strfmt.UUID5"}, 240 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.ISBN", IsPrimitive: true}}, "strfmt.ISBN"}, 241 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.ISBN10", IsPrimitive: true}}, "strfmt.ISBN10"}, 242 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.ISBN13", IsPrimitive: true}}, "strfmt.ISBN13"}, 243 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.CreditCard", IsPrimitive: true}}, "strfmt.CreditCard"}, 244 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.SSN", IsPrimitive: true}}, "strfmt.SSN"}, 245 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.HexColor", IsPrimitive: true}}, "strfmt.HexColor"}, 246 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.RGBColor", IsPrimitive: true}}, "strfmt.RGBColor"}, 247 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.Duration", IsPrimitive: true}}, "strfmt.Duration"}, 248 {GenSchema{resolvedType: resolvedType{GoType: "strfmt.Password", IsPrimitive: true}}, "strfmt.Password"}, 249 {GenSchema{resolvedType: resolvedType{GoType: "io.ReadCloser", IsStream: true}}, "io.ReadCloser"}, 250 {GenSchema{resolvedType: resolvedType{GoType: "interface{}", IsInterface: true}}, "interface{}"}, 251 {GenSchema{resolvedType: resolvedType{GoType: "[]int32", IsArray: true}}, "[]int32"}, 252 {GenSchema{resolvedType: resolvedType{GoType: "[]string", IsArray: true}}, "[]string"}, 253 {GenSchema{resolvedType: resolvedType{GoType: "map[string]int32", IsMap: true}}, "map[string]int32"}, 254 {GenSchema{resolvedType: resolvedType{GoType: "models.Task", IsComplexObject: true, IsNullable: true, IsAnonymous: false}}, "*models.Task"}, 255 } 256 257 func TestGenSchemaType(t *testing.T) { 258 tt := templateTest{t, templates.MustGet("model").Lookup("schemaType")} 259 for _, v := range schTypeGenDataSimple { 260 tt.assertRender(v.Value, v.Expected) 261 } 262 } 263 264 func TestGenerateModel_Primitives(t *testing.T) { 265 tt := templateTest{t, templates.MustGet("model").Lookup("schema")} 266 for _, v := range schTypeGenDataSimple { 267 v.Value.IncludeValidator = true 268 v.Value.IncludeModel = true 269 val := v.Value 270 val.ReceiverName = "o" 271 if val.IsComplexObject { 272 continue 273 } 274 val.Name = "theType" 275 exp := v.Expected 276 if val.IsInterface || val.IsStream { 277 tt.assertRender(&val, "type TheType "+exp+"\n \n") 278 continue 279 } 280 tt.assertRender(&val, "type TheType "+exp+"\n \n// Validate validates this the type\nfunc (o theType) Validate(formats strfmt.Registry) error {\n return nil\n}\n// ContextValidate validates this the type based on context it is used \nfunc (o theType) ContextValidate(ctx context.Context, formats strfmt.Registry) error {\n return nil\n}\n") 281 } 282 } 283 284 func TestGenerateModel_Zeroes(t *testing.T) { 285 for _, v := range schTypeGenDataSimple { 286 switch v.Value.GoType { 287 // verifying Zero for primitive 288 case "string": 289 assert.Equal(t, `""`, v.Value.Zero()) 290 case "bool": 291 assert.Equal(t, `false`, v.Value.Zero()) 292 case "int32", "int64", "float32", "float64": 293 assert.Equal(t, `0`, v.Value.Zero()) 294 // verifying Zero for primitive formatters 295 case "strfmt.Date", "strfmt.DateTime", "strfmt.OjbectId": // akin to structs 296 rex := regexp.MustCompile(regexp.QuoteMeta(v.Value.GoType) + `{}`) 297 assert.True(t, rex.MatchString(v.Value.Zero())) 298 k := v.Value 299 k.IsAliased = true 300 k.AliasedType = k.GoType 301 k.GoType = "myAliasedType" 302 rex = regexp.MustCompile(regexp.QuoteMeta(k.GoType+"("+k.AliasedType) + `{}` + `\)`) 303 assert.True(t, rex.MatchString(k.Zero())) 304 case "strfmt.Duration": // akin to integer 305 rex := regexp.MustCompile(regexp.QuoteMeta(v.Value.GoType) + `\(\d*\)`) 306 assert.True(t, rex.MatchString(v.Value.Zero())) 307 k := v.Value 308 k.IsAliased = true 309 k.AliasedType = k.GoType 310 k.GoType = "myAliasedType" 311 rex = regexp.MustCompile(regexp.QuoteMeta(k.GoType+"("+k.AliasedType) + `\(\d*\)` + `\)`) 312 assert.True(t, rex.MatchString(k.Zero())) 313 case "strfmt.Base64": // akin to []byte 314 rex := regexp.MustCompile(regexp.QuoteMeta(v.Value.GoType) + `\(\[\]byte.*\)`) 315 assert.True(t, rex.MatchString(v.Value.Zero())) 316 k := v.Value 317 k.IsAliased = true 318 k.AliasedType = k.GoType 319 k.GoType = "myAliasedType" 320 rex = regexp.MustCompile(regexp.QuoteMeta(k.GoType+"("+k.AliasedType) + `\(\[\]byte.*\)` + `\)`) 321 assert.True(t, rex.MatchString(k.Zero())) 322 case "interface{}": 323 assert.Equal(t, `nil`, v.Value.Zero()) 324 case "io.ReadCloser": 325 continue 326 default: 327 switch { 328 case strings.HasPrefix(v.Value.GoType, "[]") || strings.HasPrefix(v.Value.GoType, "map["): // akin to slice or map 329 assert.True(t, strings.HasPrefix(v.Value.Zero(), "make(")) 330 331 case strings.HasPrefix(v.Value.GoType, "models."): 332 assert.True(t, strings.HasPrefix(v.Value.Zero(), "new(")) 333 334 default: // akin to string 335 rex := regexp.MustCompile(regexp.QuoteMeta(v.Value.GoType) + `\(".*"\)`) 336 assert.True(t, rex.MatchString(v.Value.Zero())) 337 k := v.Value 338 k.IsAliased = true 339 k.AliasedType = k.GoType 340 k.GoType = "myAliasedType" 341 rex = regexp.MustCompile(regexp.QuoteMeta(k.GoType+"("+k.AliasedType) + `\(".*"\)` + `\)`) 342 assert.True(t, rex.MatchString(k.Zero())) 343 } 344 } 345 } 346 } 347 348 func TestGenerateModel_Nota(t *testing.T) { 349 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 350 require.NoError(t, err) 351 352 definitions := specDoc.Spec().Definitions 353 k := "Nota" 354 schema := definitions[k] 355 opts := opts() 356 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 357 require.NoError(t, err) 358 359 buf := bytes.NewBuffer(nil) 360 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 361 362 res := buf.String() 363 assertInCode(t, "type Nota map[string]int32", res) 364 } 365 366 func TestGenerateModel_NotaWithRef(t *testing.T) { 367 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 368 require.NoError(t, err) 369 370 definitions := specDoc.Spec().Definitions 371 k := "NotaWithRef" 372 schema := definitions[k] 373 opts := opts() 374 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 375 require.NoError(t, err) 376 377 buf := bytes.NewBuffer(nil) 378 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 379 380 ff, err := opts.LanguageOpts.FormatContent("nota_with_ref.go", buf.Bytes()) 381 require.NoError(t, err) 382 383 res := string(ff) 384 assertInCode(t, "type NotaWithRef map[string]Notable", res) 385 } 386 387 func TestGenerateModel_NotaWithMeta(t *testing.T) { 388 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 389 require.NoError(t, err) 390 391 definitions := specDoc.Spec().Definitions 392 k := "NotaWithMeta" 393 schema := definitions[k] 394 opts := opts() 395 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 396 require.NoError(t, err) 397 398 buf := bytes.NewBuffer(nil) 399 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 400 401 ff, err := opts.LanguageOpts.FormatContent("nota_with_meta.go", buf.Bytes()) 402 require.NoError(t, err) 403 404 res := string(ff) 405 assertInCode(t, "type NotaWithMeta map[string]NotaWithMetaAnon", res) 406 assertInCode(t, "type NotaWithMetaAnon struct {", res) 407 assertInCode(t, "Comment *string `json:\"comment\"`", res) 408 assertInCode(t, "Count int32 `json:\"count,omitempty\"`", res) 409 } 410 411 func TestGenerateModel_RunParameters(t *testing.T) { 412 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 413 require.NoError(t, err) 414 415 definitions := specDoc.Spec().Definitions 416 k := "RunParameters" 417 schema := definitions[k] 418 opts := opts() 419 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 420 require.NoError(t, err) 421 422 assert.False(t, genModel.IsAdditionalProperties) 423 assert.True(t, genModel.IsComplexObject) 424 assert.False(t, genModel.IsMap) 425 assert.False(t, genModel.IsAnonymous) 426 buf := bytes.NewBuffer(nil) 427 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 428 429 res := buf.String() 430 assertInCode(t, "type "+k+" struct {", res) 431 assertInCode(t, "BranchName string `json:\"branch_name,omitempty\"`", res) 432 assertInCode(t, "CommitSha string `json:\"commit_sha,omitempty\"`", res) 433 assertInCode(t, "Refs interface{} `json:\"refs,omitempty\"`", res) 434 } 435 436 func TestGenerateModel_NotaWithName(t *testing.T) { 437 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 438 require.NoError(t, err) 439 440 definitions := specDoc.Spec().Definitions 441 k := "NotaWithName" 442 schema := definitions[k] 443 opts := opts() 444 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 445 require.NoError(t, err) 446 447 assert.True(t, genModel.IsAdditionalProperties) 448 assert.False(t, genModel.IsComplexObject) 449 assert.False(t, genModel.IsMap) 450 assert.False(t, genModel.IsAnonymous) 451 buf := bytes.NewBuffer(nil) 452 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 453 454 res := buf.String() 455 assertInCode(t, "type "+k+" struct {", res) 456 assertInCode(t, k+" map[string]int32 `json:\"-\"`", res) 457 assertInCode(t, "Name *string `json:\"name\"`", res) 458 assertInCode(t, k+") UnmarshalJSON", res) 459 assertInCode(t, k+") MarshalJSON", res) 460 assertInCode(t, "json.Marshal(stage1)", res) 461 assertInCode(t, "stage1.Name = m.Name", res) 462 assertInCode(t, "json.Marshal(m."+k+")", res) 463 assertInCode(t, "json.Unmarshal(data, &stage1)", res) 464 assertInCode(t, "json.Unmarshal(data, &stage2)", res) 465 assertInCode(t, "json.Unmarshal(v, &toadd)", res) 466 assertInCode(t, "result[k] = toadd", res) 467 assertInCode(t, "m."+k+" = result", res) 468 for _, p := range genModel.Properties { 469 assertInCode(t, "delete(stage2, \""+p.Name+"\")", res) 470 } 471 } 472 473 func TestGenerateModel_NotaWithRefRegistry(t *testing.T) { 474 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 475 require.NoError(t, err) 476 477 definitions := specDoc.Spec().Definitions 478 k := "NotaWithRefRegistry" 479 schema := definitions[k] 480 opts := opts() 481 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 482 require.NoError(t, err) 483 484 buf := bytes.NewBuffer(nil) 485 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 486 487 ff, err := opts.LanguageOpts.FormatContent("nota_with_ref_registry.go", buf.Bytes()) 488 require.NoError(t, err) 489 490 assertInCode(t, "type "+k+" map[string]map[string]map[string]Notable", string(ff)) 491 } 492 493 func TestGenerateModel_WithCustomTag(t *testing.T) { 494 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 495 require.NoError(t, err) 496 497 definitions := specDoc.Spec().Definitions 498 k := "WithCustomTag" 499 schema := definitions[k] 500 opts := opts() 501 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 502 require.NoError(t, err) 503 504 buf := bytes.NewBuffer(nil) 505 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 506 507 assertInCode(t, "mytag:\"foo,bar\"", buf.String()) 508 } 509 510 func TestGenerateModel_NotaWithMetaRegistry(t *testing.T) { 511 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 512 require.NoError(t, err) 513 514 definitions := specDoc.Spec().Definitions 515 k := "NotaWithMetaRegistry" 516 schema := definitions[k] 517 opts := opts() 518 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 519 require.NoError(t, err) 520 521 buf := bytes.NewBuffer(nil) 522 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 523 524 ff, err := opts.LanguageOpts.FormatContent("nota_with_meta_registry.go", buf.Bytes()) 525 require.NoError(t, err) 526 527 res := string(ff) 528 assertInCode(t, "type "+k+" map[string]map[string]map[string]NotaWithMetaRegistryAnon", res) 529 assertInCode(t, "type NotaWithMetaRegistryAnon struct {", res) 530 assertInCode(t, "Comment *string `json:\"comment\"`", res) 531 assertInCode(t, "Count int32 `json:\"count,omitempty\"`", res) 532 } 533 534 func TestGenerateModel_WithMap(t *testing.T) { 535 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 536 require.NoError(t, err) 537 538 definitions := specDoc.Spec().Definitions 539 schema := definitions["WithMap"] 540 opts := opts() 541 genModel, err := makeGenDefinition("WithMap", "models", schema, specDoc, opts) 542 require.NoError(t, err) 543 544 assert.False(t, genModel.HasAdditionalProperties) 545 prop := getDefinitionProperty(genModel, "data") 546 assert.True(t, prop.HasAdditionalProperties) 547 assert.True(t, prop.IsMap) 548 assert.False(t, prop.IsComplexObject) 549 buf := bytes.NewBuffer(nil) 550 require.NoError(t, templates.MustGet("model").Execute(buf, genModel)) 551 552 res := buf.String() 553 assertInCode(t, "type WithMap struct {", res) 554 assertInCode(t, "Data map[string]string `json:\"data,omitempty\"`", res) 555 } 556 557 func TestGenerateModel_WithMapInterface(t *testing.T) { 558 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 559 require.NoError(t, err) 560 561 definitions := specDoc.Spec().Definitions 562 schema := definitions["WithMapInterface"] 563 opts := opts() 564 genModel, err := makeGenDefinition("WithMapInterface", "models", schema, specDoc, opts) 565 require.NoError(t, err) 566 567 assert.False(t, genModel.HasAdditionalProperties) 568 prop := getDefinitionProperty(genModel, "extraInfo") 569 assert.True(t, prop.HasAdditionalProperties) 570 assert.True(t, prop.IsMap) 571 assert.False(t, prop.IsComplexObject) 572 assert.Equal(t, "map[string]interface{}", prop.GoType) 573 assert.True(t, prop.Required) 574 assert.True(t, prop.HasValidations) 575 576 buf := bytes.NewBuffer(nil) 577 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 578 579 res := buf.String() 580 assertInCode(t, "type WithMapInterface struct {", res) 581 assertInCode(t, "ExtraInfo map[string]interface{} `json:\"extraInfo\"`", res) 582 } 583 584 func TestGenerateModel_WithMapRef(t *testing.T) { 585 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 586 require.NoError(t, err) 587 588 definitions := specDoc.Spec().Definitions 589 k := "WithMapRef" 590 schema := definitions[k] 591 opts := opts() 592 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 593 require.NoError(t, err) 594 595 assert.False(t, genModel.HasAdditionalProperties) 596 prop := getDefinitionProperty(genModel, "data") 597 assert.True(t, prop.HasAdditionalProperties) 598 assert.True(t, prop.IsMap) 599 assert.False(t, prop.IsComplexObject) 600 buf := bytes.NewBuffer(nil) 601 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 602 603 res := buf.String() 604 assertInCode(t, "type "+k+" struct {", res) 605 assertInCode(t, "Data map[string]Notable `json:\"data,omitempty\"`", res) 606 } 607 608 func TestGenerateModel_WithMapComplex(t *testing.T) { 609 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 610 require.NoError(t, err) 611 612 definitions := specDoc.Spec().Definitions 613 k := "WithMapComplex" 614 schema := definitions[k] 615 opts := opts() 616 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 617 require.NoError(t, err) 618 619 assert.False(t, genModel.HasAdditionalProperties) 620 prop := getDefinitionProperty(genModel, "data") 621 assert.True(t, prop.HasAdditionalProperties) 622 assert.True(t, prop.IsMap) 623 assert.False(t, prop.IsComplexObject) 624 buf := bytes.NewBuffer(nil) 625 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 626 627 res := buf.String() 628 assertInCode(t, "type "+k+" struct {", res) 629 assertInCode(t, "Data map[string]"+k+"DataAnon `json:\"data,omitempty\"`", res) 630 } 631 632 func TestGenerateModel_WithMapRegistry(t *testing.T) { 633 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 634 require.NoError(t, err) 635 636 definitions := specDoc.Spec().Definitions 637 schema := definitions["WithMapRegistry"] 638 opts := opts() 639 genModel, err := makeGenDefinition("WithMap", "models", schema, specDoc, opts) 640 require.NoError(t, err) 641 642 assert.False(t, genModel.HasAdditionalProperties) 643 prop := getDefinitionProperty(genModel, "data") 644 assert.True(t, prop.HasAdditionalProperties) 645 assert.True(t, prop.IsMap) 646 assert.False(t, prop.IsComplexObject) 647 buf := bytes.NewBuffer(nil) 648 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 649 650 res := buf.String() 651 assertInCode(t, "type WithMap struct {", res) 652 assertInCode(t, "Data map[string]map[string]map[string]string `json:\"data,omitempty\"`", res) 653 } 654 655 func TestGenerateModel_WithMapRegistryRef(t *testing.T) { 656 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 657 require.NoError(t, err) 658 659 definitions := specDoc.Spec().Definitions 660 k := "WithMapRegistryRef" 661 schema := definitions[k] 662 opts := opts() 663 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 664 require.NoError(t, err) 665 666 assert.False(t, genModel.HasAdditionalProperties) 667 prop := getDefinitionProperty(genModel, "data") 668 assert.True(t, prop.HasAdditionalProperties) 669 assert.True(t, prop.IsMap) 670 assert.False(t, prop.IsComplexObject) 671 buf := bytes.NewBuffer(nil) 672 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 673 674 res := buf.String() 675 assertInCode(t, "type "+k+" struct {", res) 676 assertInCode(t, "Data map[string]map[string]map[string]Notable `json:\"data,omitempty\"`", res) 677 } 678 679 func TestGenerateModel_WithMapComplexRegistry(t *testing.T) { 680 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 681 require.NoError(t, err) 682 683 definitions := specDoc.Spec().Definitions 684 k := "WithMapComplexRegistry" 685 schema := definitions[k] 686 opts := opts() 687 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 688 require.NoError(t, err) 689 690 assert.False(t, genModel.HasAdditionalProperties) 691 prop := getDefinitionProperty(genModel, "data") 692 assert.True(t, prop.HasAdditionalProperties) 693 assert.True(t, prop.IsMap) 694 assert.False(t, prop.IsComplexObject) 695 buf := bytes.NewBuffer(nil) 696 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 697 698 res := buf.String() 699 assertInCode(t, "type "+k+" struct {", res) 700 assertInCode(t, "Data map[string]map[string]map[string]"+k+"DataAnon `json:\"data,omitempty\"`", res) 701 } 702 703 func TestGenerateModel_WithAdditional(t *testing.T) { 704 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 705 require.NoError(t, err) 706 707 definitions := specDoc.Spec().Definitions 708 k := "WithAdditional" 709 schema := definitions[k] 710 opts := opts() 711 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 712 require.NoError(t, err) 713 require.NotEmpty(t, genModel.ExtraSchemas) 714 715 assert.False(t, genModel.HasAdditionalProperties) 716 assert.False(t, genModel.IsMap) 717 assert.False(t, genModel.IsAdditionalProperties) 718 assert.True(t, genModel.IsComplexObject) 719 720 sch := genModel.ExtraSchemas[0] 721 assert.True(t, sch.HasAdditionalProperties) 722 assert.False(t, sch.IsMap) 723 assert.True(t, sch.IsAdditionalProperties) 724 assert.False(t, sch.IsComplexObject) 725 726 require.NotNil(t, sch.AdditionalProperties) 727 728 prop := findProperty(genModel.Properties, "data") 729 assert.False(t, prop.HasAdditionalProperties) 730 assert.False(t, prop.IsMap) 731 assert.False(t, prop.IsAdditionalProperties) 732 assert.True(t, prop.IsComplexObject) 733 buf := bytes.NewBuffer(nil) 734 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 735 736 res := buf.String() 737 assertInCode(t, "type "+k+" struct {", res) 738 assertInCode(t, "Data *"+k+"Data `json:\"data,omitempty\"`", res) 739 assertInCode(t, "type "+k+"Data struct {", res) 740 assertInCode(t, k+"Data map[string]string `json:\"-\"`", res) 741 assertInCode(t, "Name *string `json:\"name\"`", res) 742 assertInCode(t, k+"Data) UnmarshalJSON", res) 743 assertInCode(t, k+"Data) MarshalJSON", res) 744 assertInCode(t, "json.Marshal(stage1)", res) 745 assertInCode(t, "stage1.Name = m.Name", res) 746 assertInCode(t, "json.Marshal(m."+k+"Data)", res) 747 assertInCode(t, "json.Unmarshal(data, &stage1)", res) 748 assertInCode(t, "json.Unmarshal(data, &stage2)", res) 749 assertInCode(t, "json.Unmarshal(v, &toadd)", res) 750 assertInCode(t, "result[k] = toadd", res) 751 assertInCode(t, "m."+k+"Data = result", res) 752 753 for _, p := range sch.Properties { 754 assertInCode(t, "delete(stage2, \""+p.Name+"\")", res) 755 } 756 } 757 758 func TestGenerateModel_JustRef(t *testing.T) { 759 tt := templateTest{t, templates.MustGet("model").Lookup("schema")} 760 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 761 require.NoError(t, err) 762 763 definitions := specDoc.Spec().Definitions 764 schema := definitions["JustRef"] 765 opts := opts() 766 genModel, err := makeGenDefinition("JustRef", "models", schema, specDoc, opts) 767 require.NoError(t, err) 768 769 assert.NotEmpty(t, genModel.AllOf) 770 assert.True(t, genModel.IsComplexObject) 771 assert.Equal(t, "JustRef", genModel.Name) 772 assert.Equal(t, "JustRef", genModel.GoType) 773 buf := bytes.NewBuffer(nil) 774 require.NoError(t, tt.template.Execute(buf, genModel)) 775 776 res := buf.String() 777 assertInCode(t, "type JustRef struct {", res) 778 assertInCode(t, "Notable", res) 779 } 780 781 func TestGenerateModel_WithRef(t *testing.T) { 782 tt := templateTest{t, templates.MustGet("model").Lookup("schema")} 783 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 784 require.NoError(t, err) 785 786 definitions := specDoc.Spec().Definitions 787 schema := definitions["WithRef"] 788 opts := opts() 789 genModel, err := makeGenDefinition("WithRef", "models", schema, specDoc, opts) 790 require.NoError(t, err) 791 792 assert.True(t, genModel.IsComplexObject) 793 assert.Equal(t, "WithRef", genModel.Name) 794 assert.Equal(t, "WithRef", genModel.GoType) 795 buf := bytes.NewBuffer(nil) 796 require.NoError(t, tt.template.Execute(buf, genModel)) 797 798 res := buf.String() 799 assertInCode(t, "type WithRef struct {", res) 800 assertInCode(t, "Notes *Notable `json:\"notes,omitempty\"`", res) 801 } 802 803 func TestGenerateModel_WithNullableRef(t *testing.T) { 804 tt := templateTest{t, templates.MustGet("model").Lookup("schema")} 805 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 806 require.NoError(t, err) 807 808 definitions := specDoc.Spec().Definitions 809 schema := definitions["WithNullableRef"] 810 opts := opts() 811 genModel, err := makeGenDefinition("WithNullableRef", "models", schema, specDoc, opts) 812 require.NoError(t, err) 813 814 assert.True(t, genModel.IsComplexObject) 815 assert.Equal(t, "WithNullableRef", genModel.Name) 816 assert.Equal(t, "WithNullableRef", genModel.GoType) 817 prop := getDefinitionProperty(genModel, "notes") 818 assert.True(t, prop.IsNullable) 819 assert.True(t, prop.IsComplexObject) 820 buf := bytes.NewBuffer(nil) 821 require.NoError(t, tt.template.Execute(buf, genModel)) 822 823 res := buf.String() 824 assertInCode(t, "type WithNullableRef struct {", res) 825 assertInCode(t, "Notes *Notable `json:\"notes,omitempty\"`", res) 826 } 827 828 func TestGenerateModel_Scores(t *testing.T) { 829 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 830 require.NoError(t, err) 831 832 definitions := specDoc.Spec().Definitions 833 k := "Scores" 834 schema := definitions[k] 835 opts := opts() 836 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 837 require.NoError(t, err) 838 839 buf := bytes.NewBuffer(nil) 840 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 841 842 ff, err := opts.LanguageOpts.FormatContent("scores.go", buf.Bytes()) 843 require.NoError(t, err) 844 845 assertInCode(t, "type Scores []float32", string(ff)) 846 } 847 848 func TestGenerateModel_JaggedScores(t *testing.T) { 849 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 850 require.NoError(t, err) 851 852 definitions := specDoc.Spec().Definitions 853 k := "JaggedScores" 854 schema := definitions[k] 855 opts := opts() 856 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 857 require.NoError(t, err) 858 859 buf := bytes.NewBuffer(nil) 860 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 861 862 ff, err := opts.LanguageOpts.FormatContent("jagged_scores.go", buf.Bytes()) 863 require.NoError(t, err) 864 865 assertInCode(t, "type JaggedScores [][][]float32", string(ff)) 866 } 867 868 func TestGenerateModel_Notables(t *testing.T) { 869 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 870 require.NoError(t, err) 871 872 definitions := specDoc.Spec().Definitions 873 k := "Notables" 874 schema := definitions[k] 875 opts := opts() 876 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 877 require.NoError(t, err) 878 require.Equal(t, "[]*Notable", genModel.GoType) 879 880 buf := bytes.NewBuffer(nil) 881 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 882 require.NoError(t, err) 883 884 ff, err := opts.LanguageOpts.FormatContent("notables.go", buf.Bytes()) 885 require.NoError(t, err) 886 887 res := string(ff) 888 assertInCode(t, "type Notables []*Notable", res) 889 } 890 891 func TestGenerateModel_Notablix(t *testing.T) { 892 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 893 require.NoError(t, err) 894 895 definitions := specDoc.Spec().Definitions 896 k := "Notablix" 897 schema := definitions[k] 898 opts := opts() 899 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 900 require.NoError(t, err) 901 902 buf := bytes.NewBuffer(nil) 903 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 904 905 ff, err := opts.LanguageOpts.FormatContent("notablix.go", buf.Bytes()) 906 require.NoError(t, err) 907 908 res := string(ff) 909 assertInCode(t, "type Notablix [][][]*Notable", res) 910 } 911 912 func TestGenerateModel_Stats(t *testing.T) { 913 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 914 require.NoError(t, err) 915 916 definitions := specDoc.Spec().Definitions 917 k := "Stats" 918 schema := definitions[k] 919 opts := opts() 920 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 921 require.NoError(t, err) 922 923 buf := bytes.NewBuffer(nil) 924 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 925 926 ff, err := opts.LanguageOpts.FormatContent("stats.go", buf.Bytes()) 927 require.NoError(t, err) 928 929 res := string(ff) 930 assertInCode(t, "type Stats []*StatsItems0", res) 931 assertInCode(t, "type StatsItems0 struct {", res) 932 assertInCode(t, "Points []int64 `json:\"points\"`", res) 933 } 934 935 func TestGenerateModel_Statix(t *testing.T) { 936 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 937 require.NoError(t, err) 938 939 definitions := specDoc.Spec().Definitions 940 k := "Statix" 941 schema := definitions[k] 942 opts := opts() 943 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 944 require.NoError(t, err) 945 946 buf := bytes.NewBuffer(nil) 947 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 948 949 ff, err := opts.LanguageOpts.FormatContent("statix.go", buf.Bytes()) 950 require.NoError(t, err) 951 952 res := string(ff) 953 assertInCode(t, "type Statix [][][]*StatixItems0", res) 954 assertInCode(t, "type StatixItems0 struct {", res) 955 assertInCode(t, "Points []int64 `json:\"points\"`", res) 956 } 957 958 func TestGenerateModel_WithItems(t *testing.T) { 959 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 960 require.NoError(t, err) 961 962 definitions := specDoc.Spec().Definitions 963 schema := definitions["WithItems"] 964 opts := opts() 965 tt := templateTest{t, opts.templates.MustGet("model").Lookup("schema")} 966 967 genModel, err := makeGenDefinition("WithItems", "models", schema, specDoc, opts) 968 require.NoError(t, err) 969 970 assert.Nil(t, genModel.Items) 971 assert.True(t, genModel.IsComplexObject) 972 prop := getDefinitionProperty(genModel, "tags") 973 974 assert.NotNil(t, prop.Items) 975 assert.True(t, prop.IsArray) 976 assert.False(t, prop.IsComplexObject) 977 978 buf := bytes.NewBuffer(nil) 979 require.NoError(t, tt.template.Execute(buf, genModel)) 980 981 res := buf.String() 982 assertInCode(t, "type WithItems struct {", res) 983 assertInCode(t, "Tags []string `json:\"tags\"`", res) 984 } 985 986 func TestGenerateModel_WithComplexItems(t *testing.T) { 987 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 988 require.NoError(t, err) 989 990 definitions := specDoc.Spec().Definitions 991 k := "WithComplexItems" 992 schema := definitions[k] 993 opts := opts() 994 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 995 require.NoError(t, err) 996 997 assert.Nil(t, genModel.Items) 998 assert.True(t, genModel.IsComplexObject) 999 prop := getDefinitionProperty(genModel, "tags") 1000 assert.NotNil(t, prop.Items) 1001 assert.True(t, prop.IsArray) 1002 assert.False(t, prop.IsComplexObject) 1003 buf := bytes.NewBuffer(nil) 1004 1005 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1006 1007 b, err := opts.LanguageOpts.FormatContent("with_complex_items.go", buf.Bytes()) 1008 require.NoError(t, err) 1009 1010 res := string(b) 1011 assertInCode(t, "type WithComplexItems struct {", res) 1012 assertInCode(t, "type WithComplexItemsTagsItems0 struct {", res) 1013 assertInCode(t, "Tags []*WithComplexItemsTagsItems0 `json:\"tags\"`", res) 1014 } 1015 1016 func TestGenerateModel_WithItemsAndAdditional(t *testing.T) { 1017 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1018 require.NoError(t, err) 1019 1020 definitions := specDoc.Spec().Definitions 1021 k := "WithItemsAndAdditional" 1022 schema := definitions[k] 1023 opts := opts() 1024 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1025 require.NoError(t, err) 1026 1027 assert.Nil(t, genModel.Items) 1028 assert.True(t, genModel.IsComplexObject) 1029 prop := getDefinitionProperty(genModel, "tags") 1030 assert.True(t, prop.IsComplexObject) 1031 buf := bytes.NewBuffer(nil) 1032 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1033 1034 b, err := opts.LanguageOpts.FormatContent("with_complex_items.go", buf.Bytes()) 1035 require.NoError(t, err) 1036 1037 res := string(b) 1038 assertInCode(t, "type "+k+" struct {", res) 1039 assertInCode(t, "type "+k+"TagsTuple0 struct {", res) 1040 // this would fail if it accepts additionalItems because it would come out as []interface{} 1041 assertInCode(t, "Tags *"+k+"TagsTuple0 `json:\"tags,omitempty\"`", res) 1042 assertInCode(t, "P0 *string `json:\"-\"`", res) 1043 assertInCode(t, k+"TagsTuple0Items []interface{} `json:\"-\"`", res) 1044 } 1045 1046 func TestGenerateModel_WithItemsAndAdditional2(t *testing.T) { 1047 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1048 require.NoError(t, err) 1049 1050 definitions := specDoc.Spec().Definitions 1051 k := "WithItemsAndAdditional2" 1052 schema := definitions[k] 1053 opts := opts() 1054 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1055 require.NoError(t, err) 1056 1057 assert.Nil(t, genModel.Items) 1058 assert.True(t, genModel.IsComplexObject) 1059 prop := getDefinitionProperty(genModel, "tags") 1060 assert.True(t, prop.IsComplexObject) 1061 buf := bytes.NewBuffer(nil) 1062 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1063 1064 b, err := opts.LanguageOpts.FormatContent("with_complex_items.go", buf.Bytes()) 1065 require.NoError(t, err) 1066 1067 res := string(b) 1068 assertInCode(t, "type "+k+" struct {", res) 1069 assertInCode(t, "type "+k+"TagsTuple0 struct {", res) 1070 // this would fail if it accepts additionalItems because it would come out as []interface{} 1071 assertInCode(t, "P0 *string `json:\"-\"`", res) 1072 assertInCode(t, "Tags *"+k+"TagsTuple0 `json:\"tags,omitempty\"`", res) 1073 assertInCode(t, k+"TagsTuple0Items []int32 `json:\"-\"`", res) 1074 } 1075 1076 func TestGenerateModel_WithComplexAdditional(t *testing.T) { 1077 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1078 require.NoError(t, err) 1079 1080 definitions := specDoc.Spec().Definitions 1081 k := "WithComplexAdditional" 1082 schema := definitions[k] 1083 opts := opts() 1084 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1085 require.NoError(t, err) 1086 1087 assert.Nil(t, genModel.Items) 1088 assert.True(t, genModel.IsComplexObject) 1089 prop := getDefinitionProperty(genModel, "tags") 1090 assert.True(t, prop.IsComplexObject) 1091 buf := bytes.NewBuffer(nil) 1092 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1093 1094 b, err := opts.LanguageOpts.FormatContent("with_complex_additional.go", buf.Bytes()) 1095 require.NoError(t, err) 1096 1097 res := string(b) 1098 assertInCode(t, "type WithComplexAdditional struct {", res) 1099 assertInCode(t, "type WithComplexAdditionalTagsTuple0 struct {", res) 1100 assertInCode(t, "Tags *WithComplexAdditionalTagsTuple0 `json:\"tags,omitempty\"`", res) 1101 assertInCode(t, "P0 *string `json:\"-\"`", res) 1102 assertInCode(t, "WithComplexAdditionalTagsTuple0Items []*WithComplexAdditionalTagsItems `json:\"-\"`", res) 1103 } 1104 1105 func TestGenerateModel_SimpleTuple(t *testing.T) { 1106 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1107 require.NoError(t, err) 1108 1109 definitions := specDoc.Spec().Definitions 1110 k := "SimpleTuple" 1111 schema := definitions[k] 1112 opts := opts() 1113 1114 tt := templateTest{t, opts.templates.MustGet("model")} 1115 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1116 require.NoError(t, err) 1117 require.Len(t, genModel.ExtraSchemas, 1) 1118 1119 // NOTE: with PR#1592, an extra schema is added here because of the allOf tuple element. 1120 // This uncovers another issue with special AllOfs (e.g. allOf [ ..., x-nullable:true ]) 1121 // TODO(fredbi): fix liftSpecialAllOf() to revert to: assert.Empty(t, genModel.ExtraSchemas) 1122 assert.True(t, genModel.IsTuple) 1123 assert.False(t, genModel.IsComplexObject) 1124 assert.False(t, genModel.IsArray) 1125 assert.False(t, genModel.IsAnonymous) 1126 assert.Equal(t, k, genModel.Name) 1127 assert.Equal(t, k, genModel.GoType) 1128 assert.Len(t, genModel.Properties, 5) 1129 buf := bytes.NewBuffer(nil) 1130 require.NoError(t, tt.template.Execute(buf, genModel)) 1131 1132 res := buf.String() 1133 assertInCode(t, "swagger:model "+k, res) 1134 assertInCode(t, "type "+k+" struct {", res) 1135 assertInCode(t, "P0 *int64 `json:\"-\"`", res) 1136 assertInCode(t, "P1 *string `json:\"-\"`", res) 1137 assertInCode(t, "P2 *strfmt.DateTime `json:\"-\"`", res) 1138 assertInCode(t, "P3 *Notable `json:\"-\"`", res) 1139 // NOTE: with PR#1592, an extra schema is added here because of the allOf tuple element. 1140 // This uncovers another issue with special AllOfs (e.g. allOf [ ..., x-nullable:true ]) 1141 // TODO(fredbi): fix liftSpecialAllOf() to revert to: assert.Empty(t, genModel.ExtraSchemas) 1142 // assertInCode(t, "P4 *Notable `json:\"-\"`", res) 1143 assertInCode(t, "P4 *SimpleTupleItems4 `json:\"-\"`", res) 1144 assertInCode(t, k+") UnmarshalJSON", res) 1145 assertInCode(t, k+") MarshalJSON", res) 1146 assertInCode(t, "json.Marshal(data)", res) 1147 assert.NotRegexp(t, regexp.MustCompile("lastIndex"), res) 1148 1149 for i, p := range genModel.Properties { 1150 m := "m.P" + strconv.Itoa(i) 1151 r := "&dataP" + strconv.Itoa(i) 1152 var rr string 1153 if !p.IsNullable { 1154 rr = "dataP" + strconv.Itoa(i) 1155 } else { 1156 rr = r 1157 } 1158 assertInCode(t, fmt.Sprintf("buf = bytes.NewBuffer(stage1[%d])", i), res) 1159 assertInCode(t, fmt.Sprintf("dec.Decode(%s)", r), res) 1160 assertInCode(t, "P"+strconv.Itoa(i)+",", res) 1161 assertInCode(t, fmt.Sprintf("%s = %s", m, rr), res) 1162 } 1163 } 1164 1165 func TestGenerateModel_TupleWithExtra(t *testing.T) { 1166 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1167 require.NoError(t, err) 1168 1169 definitions := specDoc.Spec().Definitions 1170 k := "TupleWithExtra" 1171 schema := definitions[k] 1172 opts := opts() 1173 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1174 require.NoError(t, err) 1175 require.Empty(t, genModel.ExtraSchemas) 1176 1177 assert.True(t, genModel.IsTuple) 1178 assert.False(t, genModel.IsComplexObject) 1179 assert.False(t, genModel.IsArray) 1180 assert.False(t, genModel.IsAnonymous) 1181 assert.True(t, genModel.HasAdditionalItems) 1182 assert.NotNil(t, genModel.AdditionalItems) 1183 assert.Equal(t, k, genModel.Name) 1184 assert.Equal(t, k, genModel.GoType) 1185 assert.Len(t, genModel.Properties, 4) 1186 buf := bytes.NewBuffer(nil) 1187 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1188 1189 ff, err := opts.LanguageOpts.FormatContent("tuple_with_extra.go", buf.Bytes()) 1190 require.NoError(t, err) 1191 1192 res := string(ff) 1193 assertInCode(t, "swagger:model "+k, res) 1194 assertInCode(t, "type "+k+" struct {", res) 1195 assertInCode(t, "P0 *int64 `json:\"-\"`", res) 1196 assertInCode(t, "P1 *string `json:\"-\"`", res) 1197 assertInCode(t, "P2 *strfmt.DateTime `json:\"-\"`", res) 1198 assertInCode(t, "P3 *Notable `json:\"-\"`", res) 1199 assertInCode(t, k+"Items []float64 `json:\"-\"`", res) 1200 assertInCode(t, k+") UnmarshalJSON", res) 1201 assertInCode(t, k+") MarshalJSON", res) 1202 1203 for i, p := range genModel.Properties { 1204 m := "m.P" + strconv.Itoa(i) 1205 r := "&dataP" + strconv.Itoa(i) 1206 var rr string 1207 if !p.IsNullable { 1208 rr = "dataP" + strconv.Itoa(i) 1209 } else { 1210 rr = r 1211 } 1212 assertInCode(t, fmt.Sprintf("lastIndex = %d", i), res) 1213 assertInCode(t, fmt.Sprintf("buf = bytes.NewBuffer(stage1[%d])", i), res) 1214 assertInCode(t, "dec := json.NewDecoder(buf)", res) 1215 assertInCode(t, fmt.Sprintf("dec.Decode(%s)", r), res) 1216 assertInCode(t, "P"+strconv.Itoa(i)+",", res) 1217 assertInCode(t, fmt.Sprintf("%s = %s", m, rr), res) 1218 } 1219 1220 assertInCode(t, "var lastIndex int", res) 1221 assertInCode(t, "var toadd float64", res) 1222 assertInCode(t, "for _, val := range stage1[lastIndex+1:]", res) 1223 assertInCode(t, "buf = bytes.NewBuffer(val)", res) 1224 assertInCode(t, "dec := json.NewDecoder(buf)", res) 1225 assertInCode(t, "dec.Decode(&toadd)", res) 1226 assertInCode(t, "json.Marshal(data)", res) 1227 assertInCode(t, "for _, v := range m."+k+"Items", res) 1228 } 1229 1230 func TestGenerateModel_TupleWithComplex(t *testing.T) { 1231 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1232 require.NoError(t, err) 1233 1234 definitions := specDoc.Spec().Definitions 1235 k := "TupleWithComplex" 1236 schema := definitions[k] 1237 opts := opts() 1238 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1239 require.NoError(t, err) 1240 1241 assert.True(t, genModel.IsTuple) 1242 assert.False(t, genModel.IsComplexObject) 1243 assert.False(t, genModel.IsArray) 1244 assert.False(t, genModel.IsAnonymous) 1245 assert.True(t, genModel.HasAdditionalItems) 1246 assert.NotNil(t, genModel.AdditionalItems) 1247 assert.Equal(t, k, genModel.Name) 1248 assert.Equal(t, k, genModel.GoType) 1249 assert.Len(t, genModel.Properties, 4) 1250 buf := bytes.NewBuffer(nil) 1251 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1252 1253 ff, err := opts.LanguageOpts.FormatContent("tuple_with_extra.go", buf.Bytes()) 1254 require.NoError(t, err) 1255 1256 res := string(ff) 1257 assertInCode(t, "swagger:model "+k, res) 1258 assertInCode(t, "type "+k+" struct {", res) 1259 assertInCode(t, "P0 *int64 `json:\"-\"`", res) 1260 assertInCode(t, "P1 *string `json:\"-\"`", res) 1261 assertInCode(t, "P2 *strfmt.DateTime `json:\"-\"`", res) 1262 assertInCode(t, "P3 *Notable `json:\"-\"`", res) 1263 assertInCode(t, k+"Items []*TupleWithComplexItems `json:\"-\"`", res) 1264 assertInCode(t, k+") UnmarshalJSON", res) 1265 assertInCode(t, k+") MarshalJSON", res) 1266 1267 for i, p := range genModel.Properties { 1268 m := "m.P" + strconv.Itoa(i) 1269 r := "&dataP" + strconv.Itoa(i) 1270 var rr string 1271 if !p.IsNullable { 1272 rr = "dataP" + strconv.Itoa(i) 1273 } else { 1274 rr = r 1275 } 1276 assertInCode(t, fmt.Sprintf("lastIndex = %d", i), res) 1277 assertInCode(t, fmt.Sprintf("buf = bytes.NewBuffer(stage1[%d])", i), res) 1278 assertInCode(t, "dec := json.NewDecoder(buf)", res) 1279 assertInCode(t, fmt.Sprintf("dec.Decode(%s)", r), res) 1280 assertInCode(t, "P"+strconv.Itoa(i)+",", res) 1281 assertInCode(t, fmt.Sprintf("%s = %s", m, rr), res) 1282 } 1283 1284 assertInCode(t, "var lastIndex int", res) 1285 assertInCode(t, "var toadd *TupleWithComplexItems", res) 1286 assertInCode(t, "for _, val := range stage1[lastIndex+1:]", res) 1287 assertInCode(t, "buf = bytes.NewBuffer(val)", res) 1288 assertInCode(t, "dec := json.NewDecoder(buf)", res) 1289 assertInCode(t, "dec.Decode(toadd)", res) 1290 assertInCode(t, "json.Marshal(data)", res) 1291 assertInCode(t, "for _, v := range m."+k+"Items", res) 1292 } 1293 1294 func TestGenerateModel_WithTuple(t *testing.T) { 1295 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1296 require.NoError(t, err) 1297 1298 definitions := specDoc.Spec().Definitions 1299 k := "WithTuple" 1300 schema := definitions[k] 1301 opts := opts() 1302 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1303 require.NoError(t, err) 1304 require.NotEmpty(t, genModel.ExtraSchemas) 1305 require.NotEmpty(t, genModel.Properties) 1306 1307 assert.False(t, genModel.IsTuple) 1308 assert.True(t, genModel.IsComplexObject) 1309 assert.False(t, genModel.IsArray) 1310 assert.False(t, genModel.IsAnonymous) 1311 1312 sch := genModel.ExtraSchemas[0] 1313 assert.True(t, sch.IsTuple) 1314 assert.False(t, sch.IsComplexObject) 1315 assert.False(t, sch.IsArray) 1316 assert.False(t, sch.IsAnonymous) 1317 assert.Equal(t, k+"FlagsTuple0", sch.Name) 1318 assert.False(t, sch.HasAdditionalItems) 1319 assert.Nil(t, sch.AdditionalItems) 1320 1321 prop := genModel.Properties[0] 1322 assert.False(t, genModel.IsTuple) 1323 assert.True(t, genModel.IsComplexObject) 1324 assert.False(t, prop.IsArray) 1325 assert.False(t, prop.IsAnonymous) 1326 assert.Equal(t, k+"FlagsTuple0", prop.GoType) 1327 assert.Equal(t, "flags", prop.Name) 1328 buf := bytes.NewBuffer(nil) 1329 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1330 1331 ff, err := opts.LanguageOpts.FormatContent("with_tuple.go", buf.Bytes()) 1332 require.NoError(t, err) 1333 1334 res := string(ff) 1335 assertInCode(t, "swagger:model "+k+"Flags", res) 1336 assertInCode(t, "type "+k+"FlagsTuple0 struct {", res) 1337 assertInCode(t, "P0 *int64 `json:\"-\"`", res) 1338 assertInCode(t, "P1 *string `json:\"-\"`", res) 1339 assertInCode(t, k+"FlagsTuple0) UnmarshalJSON", res) 1340 assertInCode(t, k+"FlagsTuple0) MarshalJSON", res) 1341 assertInCode(t, "json.Marshal(data)", res) 1342 assert.NotRegexp(t, regexp.MustCompile("lastIndex"), res) 1343 1344 for i, p := range sch.Properties { 1345 m := "m.P" + strconv.Itoa(i) 1346 r := "&dataP" + strconv.Itoa(i) 1347 var rr string 1348 if !p.IsNullable { 1349 rr = "dataP" + strconv.Itoa(i) 1350 } else { 1351 rr = r 1352 } 1353 assertInCode(t, fmt.Sprintf("buf = bytes.NewBuffer(stage1[%d])", i), res) 1354 assertInCode(t, "dec := json.NewDecoder(buf)", res) 1355 assertInCode(t, fmt.Sprintf("dec.Decode(%s)", r), res) 1356 assertInCode(t, "P"+strconv.Itoa(i)+",", res) 1357 assertInCode(t, fmt.Sprintf("%s = %s", m, rr), res) 1358 } 1359 } 1360 1361 func TestGenerateModel_WithTupleWithExtra(t *testing.T) { 1362 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1363 require.NoError(t, err) 1364 1365 definitions := specDoc.Spec().Definitions 1366 k := "WithTupleWithExtra" 1367 schema := definitions[k] 1368 opts := opts() 1369 tt := templateTest{t, opts.templates.MustGet("model")} 1370 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 1371 require.NoError(t, err) 1372 require.NotEmpty(t, genModel.ExtraSchemas) 1373 require.NotEmpty(t, genModel.Properties) 1374 1375 assert.False(t, genModel.IsTuple) 1376 assert.True(t, genModel.IsComplexObject) 1377 assert.False(t, genModel.IsArray) 1378 assert.False(t, genModel.IsAnonymous) 1379 1380 sch := genModel.ExtraSchemas[0] 1381 assert.True(t, sch.IsTuple) 1382 assert.False(t, sch.IsComplexObject) 1383 assert.False(t, sch.IsArray) 1384 assert.False(t, sch.IsAnonymous) 1385 assert.Equal(t, k+"FlagsTuple0", sch.Name) 1386 assert.True(t, sch.HasAdditionalItems) 1387 assert.NotEmpty(t, sch.AdditionalItems) 1388 1389 prop := genModel.Properties[0] 1390 assert.False(t, genModel.IsTuple) 1391 assert.True(t, genModel.IsComplexObject) 1392 assert.False(t, prop.IsArray) 1393 assert.False(t, prop.IsAnonymous) 1394 assert.Equal(t, k+"FlagsTuple0", prop.GoType) 1395 assert.Equal(t, "flags", prop.Name) 1396 buf := bytes.NewBuffer(nil) 1397 require.NoError(t, tt.template.Execute(buf, genModel)) 1398 1399 ff, err := opts.LanguageOpts.FormatContent("with_tuple.go", buf.Bytes()) 1400 require.NoError(t, err) 1401 1402 res := string(ff) 1403 assertInCode(t, "swagger:model "+k+"Flags", res) 1404 assertInCode(t, "type "+k+"FlagsTuple0 struct {", res) 1405 assertInCode(t, "P0 *int64 `json:\"-\"`", res) 1406 assertInCode(t, "P1 *string `json:\"-\"`", res) 1407 assertInCode(t, k+"FlagsTuple0Items []float32 `json:\"-\"`", res) 1408 assertInCode(t, k+"FlagsTuple0) UnmarshalJSON", res) 1409 assertInCode(t, k+"FlagsTuple0) MarshalJSON", res) 1410 assertInCode(t, "json.Marshal(data)", res) 1411 1412 for i, p := range sch.Properties { 1413 m := "m.P" + strconv.Itoa(i) 1414 r := "&dataP" + strconv.Itoa(i) 1415 var rr string 1416 if !p.IsNullable { 1417 rr = "dataP" + strconv.Itoa(i) 1418 } else { 1419 rr = r 1420 } 1421 assertInCode(t, fmt.Sprintf("lastIndex = %d", i), res) 1422 assertInCode(t, fmt.Sprintf("buf = bytes.NewBuffer(stage1[%d])", i), res) 1423 assertInCode(t, "dec := json.NewDecoder(buf)", res) 1424 assertInCode(t, fmt.Sprintf("dec.Decode(%s)", r), res) 1425 assertInCode(t, "P"+strconv.Itoa(i)+",", res) 1426 assertInCode(t, fmt.Sprintf("%s = %s", m, rr), res) 1427 } 1428 1429 assertInCode(t, "var lastIndex int", res) 1430 assertInCode(t, "var toadd float32", res) 1431 assertInCode(t, "for _, val := range stage1[lastIndex+1:]", res) 1432 assertInCode(t, "buf = bytes.NewBuffer(val)", res) 1433 assertInCode(t, "dec := json.NewDecoder(buf)", res) 1434 assertInCode(t, "dec.Decode(&toadd)", res) 1435 assertInCode(t, "json.Marshal(data)", res) 1436 assertInCode(t, "for _, v := range m."+k+"FlagsTuple0Items", res) 1437 } 1438 1439 func TestGenerateModel_WithAllOfAndDiscriminator(t *testing.T) { 1440 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1441 require.NoError(t, err) 1442 1443 definitions := specDoc.Spec().Definitions 1444 schema := definitions["Cat"] 1445 opts := opts() 1446 genModel, err := makeGenDefinition("Cat", "models", schema, specDoc, opts) 1447 require.NoError(t, err) 1448 require.Len(t, genModel.AllOf, 2) 1449 1450 assert.True(t, genModel.IsComplexObject) 1451 assert.Equal(t, "Cat", genModel.Name) 1452 assert.Equal(t, "Cat", genModel.GoType) 1453 buf := bytes.NewBuffer(nil) 1454 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1455 1456 ct, err := opts.LanguageOpts.FormatContent("cat.go", buf.Bytes()) 1457 require.NoError(t, err) 1458 1459 res := string(ct) 1460 assertInCode(t, "type Cat struct {", res) 1461 assertInCode(t, "Pet", res) 1462 assertInCode(t, "HuntingSkill *string `json:\"huntingSkill\"`", res) 1463 } 1464 1465 func TestGenerateModel_WithAllOfAndDiscriminatorAndArrayOfPolymorphs(t *testing.T) { 1466 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1467 require.NoError(t, err) 1468 1469 definitions := specDoc.Spec().Definitions 1470 schema := definitions["PetWithPets"] 1471 opts := opts() 1472 genModel, err := makeGenDefinition("PetWithPets", "models", schema, specDoc, opts) 1473 require.NoError(t, err) 1474 require.Len(t, genModel.AllOf, 2) 1475 1476 assert.True(t, genModel.IsComplexObject) 1477 assert.Equal(t, "PetWithPets", genModel.Name) 1478 assert.Equal(t, "PetWithPets", genModel.GoType) 1479 buf := bytes.NewBuffer(nil) 1480 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1481 1482 ct, err := opts.LanguageOpts.FormatContent("PetWithPets.go", buf.Bytes()) 1483 require.NoError(t, err) 1484 1485 res := string(ct) 1486 assertInCode(t, "type PetWithPets struct {", res) 1487 assertInCode(t, "UnmarshalPetSlice", res) 1488 } 1489 1490 func TestGenerateModel_WithAllOf(t *testing.T) { 1491 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1492 require.NoError(t, err) 1493 1494 definitions := specDoc.Spec().Definitions 1495 schema := definitions["WithAllOf"] 1496 opts := opts() 1497 genModel, err := makeGenDefinition("WithAllOf", "models", schema, specDoc, opts) 1498 require.NoError(t, err) 1499 1500 assert.Len(t, genModel.AllOf, 7) 1501 assert.True(t, genModel.AllOf[1].HasAdditionalProperties) 1502 assert.True(t, genModel.IsComplexObject) 1503 assert.Equal(t, "WithAllOf", genModel.Name) 1504 assert.Equal(t, "WithAllOf", genModel.GoType) 1505 buf := bytes.NewBuffer(nil) 1506 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1507 1508 ct, err := opts.LanguageOpts.FormatContent("all_of_schema.go", buf.Bytes()) 1509 require.NoError(t, err) 1510 1511 res := string(ct) 1512 assertInCode(t, "type WithAllOf struct {", res) 1513 assertInCode(t, "type WithAllOfAO2P2 struct {", res) 1514 assertInCode(t, "type WithAllOfAO3P3 struct {", res) 1515 assertInCode(t, "type WithAllOfParamsAnon struct {", res) 1516 assertInCode(t, "type WithAllOfAO4Tuple4 struct {", res) 1517 assertInCode(t, "type WithAllOfAO5Tuple5 struct {", res) 1518 assertInCode(t, "Notable", res) 1519 assertInCode(t, "Title string `json:\"title,omitempty\"`", res) 1520 assertInCode(t, "Body string `json:\"body,omitempty\"`", res) 1521 assertInCode(t, "Name string `json:\"name,omitempty\"`", res) 1522 assertInCode(t, "P0 *float32 `json:\"-\"`", res) 1523 assertInCode(t, "P0 *float64 `json:\"-\"`", res) 1524 assertInCode(t, "P1 *strfmt.DateTime `json:\"-\"`", res) 1525 assertInCode(t, "P1 *strfmt.Date `json:\"-\"`", res) 1526 assertInCode(t, "Opinion string `json:\"opinion,omitempty\"`", res) 1527 assertInCode(t, "WithAllOfAO5Tuple5Items []strfmt.Password `json:\"-\"`", res) 1528 assertInCode(t, "AO1 map[string]int32 `json:\"-\"`", res) 1529 assertInCode(t, "WithAllOfAO2P2 map[string]int64 `json:\"-\"`", res) 1530 } 1531 1532 func findProperty(properties []GenSchema, name string) *GenSchema { 1533 for _, p := range properties { 1534 if p.Name == name { 1535 return &p 1536 } 1537 } 1538 return nil 1539 } 1540 1541 func getDefinitionProperty(genModel *GenDefinition, name string) *GenSchema { 1542 return findProperty(genModel.Properties, name) 1543 } 1544 1545 func TestNumericKeys(t *testing.T) { 1546 specDoc, err := loads.Spec("../fixtures/bugs/162/swagger.yml") 1547 require.NoError(t, err) 1548 1549 definitions := specDoc.Spec().Definitions 1550 schema := definitions["AvatarUrls"] 1551 opts := opts() 1552 genModel, err := makeGenDefinition("AvatarUrls", "models", schema, specDoc, opts) 1553 require.NoError(t, err) 1554 1555 buf := bytes.NewBuffer(nil) 1556 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1557 1558 ct, err := opts.LanguageOpts.FormatContent("all_of_schema.go", buf.Bytes()) 1559 require.NoError(t, err) 1560 1561 res := string(ct) 1562 assertInCode(t, "Nr16x16 string `json:\"16x16,omitempty\"`", res) 1563 } 1564 1565 func TestGenModel_Issue196(t *testing.T) { 1566 specDoc, err := loads.Spec("../fixtures/bugs/196/swagger.yml") 1567 require.NoError(t, err) 1568 1569 definitions := specDoc.Spec().Definitions 1570 schema := definitions["Event"] 1571 opts := opts() 1572 genModel, err := makeGenDefinition("Event", "models", schema, specDoc, opts) 1573 require.NoError(t, err) 1574 1575 buf := bytes.NewBuffer(nil) 1576 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1577 1578 ct, err := opts.LanguageOpts.FormatContent("primitive_event.go", buf.Bytes()) 1579 require.NoError(t, err) 1580 1581 res := string(ct) 1582 assertInCode(t, "Event) Validate(formats strfmt.Registry) error", res) 1583 } 1584 1585 func TestGenModel_Issue222(t *testing.T) { 1586 specDoc, err := loads.Spec("../fixtures/codegen/tasklist.basic.yml") 1587 require.NoError(t, err) 1588 1589 definitions := specDoc.Spec().Definitions 1590 k := "Price" 1591 opts := opts() 1592 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1593 require.NoError(t, err) 1594 require.True(t, genModel.HasValidations) 1595 1596 buf := bytes.NewBuffer(nil) 1597 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1598 1599 ct, err := opts.LanguageOpts.FormatContent("price.go", buf.Bytes()) 1600 require.NoError(t, err) 1601 1602 res := string(ct) 1603 assertInCode(t, "Price) Validate(formats strfmt.Registry) error", res) 1604 assertInCode(t, "Currency Currency `json:\"currency,omitempty\"`", res) 1605 assertInCode(t, "m.Currency.Validate(formats); err != nil", res) 1606 } 1607 1608 func TestGenModel_Issue243(t *testing.T) { 1609 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1610 require.NoError(t, err) 1611 1612 definitions := specDoc.Spec().Definitions 1613 k := "HasDynMeta" 1614 opts := opts() 1615 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1616 require.NoError(t, err) 1617 1618 buf := bytes.NewBuffer(nil) 1619 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1620 1621 ct, err := opts.LanguageOpts.FormatContent("has_dyn_meta.go", buf.Bytes()) 1622 require.NoError(t, err) 1623 1624 res := string(ct) 1625 assertInCode(t, "Metadata DynamicMetaData `json:\"metadata,omitempty\"`", res) 1626 } 1627 1628 func TestGenModel_Issue252(t *testing.T) { 1629 specDoc, err := loads.Spec("../fixtures/bugs/252/swagger.json") 1630 require.NoError(t, err) 1631 1632 definitions := specDoc.Spec().Definitions 1633 k := "SodaBrand" 1634 opts := opts() 1635 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1636 require.NoError(t, err) 1637 require.False(t, genModel.IsNullable) 1638 1639 buf := bytes.NewBuffer(nil) 1640 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1641 1642 ct, err := opts.LanguageOpts.FormatContent("soda_brand.go", buf.Bytes()) 1643 require.NoError(t, err) 1644 1645 res := string(ct) 1646 assertInCode(t, "type "+k+" string", res) 1647 assertInCode(t, "(m "+k+") validateSodaBrand", res) 1648 assertInCode(t, "(m "+k+") Validate", res) 1649 } 1650 1651 func TestGenModel_Issue251(t *testing.T) { 1652 specDoc, err := loads.Spec("../fixtures/bugs/251/swagger.yml") 1653 require.NoError(t, err) 1654 1655 definitions := specDoc.Spec().Definitions 1656 k := "example" 1657 opts := opts() 1658 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1659 require.NoError(t, err) 1660 1661 buf := bytes.NewBuffer(nil) 1662 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1663 1664 ct, err := opts.LanguageOpts.FormatContent("example.go", buf.Bytes()) 1665 require.NoError(t, err) 1666 1667 res := string(ct) 1668 1669 assertInCode(t, "type "+swag.ToGoName(k)+" struct", res) 1670 assertInCode(t, "Begin *strfmt.DateTime `json:\"begin\"`", res) 1671 assertInCode(t, "End strfmt.DateTime `json:\"end,omitempty\"`", res) 1672 assertInCode(t, "Name string `json:\"name,omitempty\"`", res) 1673 assertInCode(t, "(m *"+swag.ToGoName(k)+") validateBegin", res) 1674 assertInCode(t, "(m *"+swag.ToGoName(k)+") Validate", res) 1675 } 1676 1677 func TestGenModel_Issue257(t *testing.T) { 1678 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1679 require.NoError(t, err) 1680 1681 definitions := specDoc.Spec().Definitions 1682 k := "HasSpecialCharProp" 1683 opts := opts() 1684 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1685 require.NoError(t, err) 1686 1687 buf := bytes.NewBuffer(nil) 1688 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1689 1690 ct, err := opts.LanguageOpts.FormatContent("example.go", buf.Bytes()) 1691 require.NoError(t, err) 1692 1693 res := string(ct) 1694 1695 assertInCode(t, "type "+swag.ToGoName(k)+" struct", res) 1696 assertInCode(t, "AtType string `json:\"@type,omitempty\"`", res) 1697 assertInCode(t, "Type string `json:\"type,omitempty\"`", res) 1698 } 1699 1700 func TestGenModel_Issue340(t *testing.T) { 1701 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1702 require.NoError(t, err) 1703 1704 definitions := specDoc.Spec().Definitions 1705 k := "ImageTar" 1706 opts := opts() 1707 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1708 require.NoError(t, err) 1709 1710 buf := bytes.NewBuffer(nil) 1711 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1712 1713 ct, err := opts.LanguageOpts.FormatContent("image_tar.go", buf.Bytes()) 1714 require.NoError(t, err) 1715 1716 res := string(ct) 1717 1718 assertInCode(t, "type "+swag.ToGoName(k)+" io.ReadCloser", res) 1719 assertNotInCode(t, "func (m ImageTar) Validate(formats strfmt.Registry) error", res) 1720 } 1721 1722 func TestGenModel_Issue381(t *testing.T) { 1723 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1724 require.NoError(t, err) 1725 1726 definitions := specDoc.Spec().Definitions 1727 k := "flags_list" 1728 opts := opts() 1729 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1730 require.NoError(t, err) 1731 1732 buf := bytes.NewBuffer(nil) 1733 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1734 1735 ct, err := opts.LanguageOpts.FormatContent("flags_list.go", buf.Bytes()) 1736 require.NoError(t, err) 1737 1738 res := string(ct) 1739 assertNotInCode(t, "m[i] != nil", res) 1740 } 1741 1742 func TestGenModel_Issue300(t *testing.T) { 1743 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1744 require.NoError(t, err) 1745 1746 definitions := specDoc.Spec().Definitions 1747 k := "ActionItem" 1748 opts := opts() 1749 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1750 require.NoError(t, err) 1751 1752 buf := bytes.NewBuffer(nil) 1753 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1754 1755 ct, err := opts.LanguageOpts.FormatContent("action_item.go", buf.Bytes()) 1756 require.NoError(t, err) 1757 1758 res := string(ct) 1759 assertInCode(t, "Name ActionName `json:\"name\"`", res) 1760 } 1761 1762 func TestGenModel_Issue398(t *testing.T) { 1763 specDoc, err := loads.Spec("../fixtures/codegen/todolist.models.yml") 1764 require.NoError(t, err) 1765 1766 definitions := specDoc.Spec().Definitions 1767 k := "Property" 1768 opts := opts() 1769 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1770 require.NoError(t, err) 1771 1772 buf := bytes.NewBuffer(nil) 1773 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1774 1775 ct, err := opts.LanguageOpts.FormatContent("action_item.go", buf.Bytes()) 1776 require.NoError(t, err) 1777 1778 res := string(ct) 1779 assertInCode(t, "Computed bool `json:\"computed,omitempty\"`", res) 1780 assertInCode(t, "Intval *int64 `json:\"intval\"`", res) 1781 assertInCode(t, "PropType *string `json:\"propType\"`", res) 1782 assertInCode(t, "Strval *string `json:\"strval\"`", res) 1783 } 1784 1785 func TestGenModel_Issue454(t *testing.T) { 1786 specDoc, err := loads.Spec("../fixtures/bugs/454/swagger.yml") 1787 require.NoError(t, err) 1788 1789 definitions := specDoc.Spec().Definitions 1790 schema := definitions["genericResource"] 1791 opts := opts() 1792 genModel, err := makeGenDefinition("genericResource", "models", schema, specDoc, opts) 1793 require.NoError(t, err) 1794 1795 buf := bytes.NewBuffer(nil) 1796 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1797 1798 ct, err := opts.LanguageOpts.FormatContent("generic_resource.go", buf.Bytes()) 1799 require.NoError(t, err) 1800 1801 res := string(ct) 1802 assertInCode(t, "rcv.Meta = stage1.Meta", res) 1803 assertInCode(t, "json.Marshal(stage1)", res) 1804 assertInCode(t, "stage1.Meta = m.Meta", res) 1805 assertInCode(t, "json.Marshal(m.GenericResource)", res) 1806 } 1807 1808 func TestGenModel_Issue423(t *testing.T) { 1809 specDoc, err := loads.Spec("../fixtures/bugs/423/swagger.json") 1810 require.NoError(t, err) 1811 1812 definitions := specDoc.Spec().Definitions 1813 schema := definitions["SRN"] 1814 opts := opts() 1815 genModel, err := makeGenDefinition("SRN", "models", schema, specDoc, opts) 1816 require.NoError(t, err) 1817 1818 buf := bytes.NewBuffer(nil) 1819 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1820 1821 ct, err := opts.LanguageOpts.FormatContent("SRN.go", buf.Bytes()) 1822 require.NoError(t, err) 1823 1824 res := string(ct) 1825 assertInCode(t, "propSite, err := UnmarshalSite(bytes.NewBuffer(data.Site), runtime.JSONConsumer())", res) 1826 assertInCode(t, "result.siteField = propSite", res) 1827 } 1828 1829 func TestGenModel_Issue453(t *testing.T) { 1830 specDoc, err := loads.Spec("../fixtures/bugs/453/swagger.yml") 1831 require.NoError(t, err) 1832 1833 definitions := specDoc.Spec().Definitions 1834 k := "out_obj" 1835 opts := opts() 1836 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1837 require.NoError(t, err) 1838 1839 buf := bytes.NewBuffer(nil) 1840 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1841 1842 ct, err := opts.LanguageOpts.FormatContent("out_obj.go", buf.Bytes()) 1843 require.NoError(t, err) 1844 1845 res := string(ct) 1846 assertInCode(t, `func (m *OutObj) validateFld3(formats strfmt.Registry)`, res) 1847 } 1848 1849 func TestGenModel_Issue455(t *testing.T) { 1850 specDoc, err := loads.Spec("../fixtures/bugs/455/swagger.yml") 1851 require.NoError(t, err) 1852 1853 definitions := specDoc.Spec().Definitions 1854 k := "out_obj" 1855 opts := opts() 1856 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1857 require.NoError(t, err) 1858 1859 buf := bytes.NewBuffer(nil) 1860 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1861 1862 ct, err := opts.LanguageOpts.FormatContent("out_obj.go", buf.Bytes()) 1863 require.NoError(t, err) 1864 1865 res := string(ct) 1866 assertInCode(t, `if err := validate.Required("fld2", "body", m.Fld2); err != nil {`, res) 1867 } 1868 1869 func TestGenModel_Issue763(t *testing.T) { 1870 specDoc, err := loads.Spec("../fixtures/bugs/763/swagger.yml") 1871 require.NoError(t, err) 1872 1873 definitions := specDoc.Spec().Definitions 1874 k := "test_list" 1875 opts := opts() 1876 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1877 require.NoError(t, err) 1878 1879 buf := bytes.NewBuffer(nil) 1880 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1881 1882 ct, err := opts.LanguageOpts.FormatContent("test_list.go", buf.Bytes()) 1883 require.NoError(t, err) 1884 1885 res := string(ct) 1886 assertInCode(t, "TheArray []*int32 `json:\"the_array\"`", res) 1887 assertInCode(t, `validate.MinimumInt("the_array"+"."+strconv.Itoa(i), "body", int64(*m.TheArray[i]), 0, false)`, res) 1888 assertInCode(t, `validate.MaximumInt("the_array"+"."+strconv.Itoa(i), "body", int64(*m.TheArray[i]), 10, false)`, res) 1889 } 1890 1891 func TestGenModel_Issue811_NullType(t *testing.T) { 1892 specDoc, err := loads.Spec("../fixtures/bugs/811/swagger.json") 1893 require.NoError(t, err) 1894 1895 definitions := specDoc.Spec().Definitions 1896 k := "teamRepos" 1897 opts := opts() 1898 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1899 require.NoError(t, err) 1900 1901 buf := bytes.NewBuffer(nil) 1902 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1903 1904 ct, err := opts.LanguageOpts.FormatContent("team_repos.go", buf.Bytes()) 1905 require.NoError(t, err) 1906 1907 res := string(ct) 1908 assertInCode(t, "Language interface{} `json:\"language,omitempty\"`", res) 1909 } 1910 1911 func TestGenModel_Issue811_Emojis(t *testing.T) { 1912 specDoc, err := loads.Spec("../fixtures/bugs/811/swagger.json") 1913 require.NoError(t, err) 1914 1915 definitions := specDoc.Spec().Definitions 1916 k := "emojis" 1917 opts := opts() 1918 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1919 require.NoError(t, err) 1920 1921 buf := bytes.NewBuffer(nil) 1922 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1923 1924 ct, err := opts.LanguageOpts.FormatContent("team_repos.go", buf.Bytes()) 1925 require.NoError(t, err) 1926 1927 res := string(ct) 1928 assertInCode(t, "Plus1 string `json:\"+1,omitempty\"`", res) 1929 assertInCode(t, "Minus1 string `json:\"-1,omitempty\"`", res) 1930 } 1931 1932 func TestGenModel_Issue752_EOFErr(t *testing.T) { 1933 specDoc, err := loads.Spec("../fixtures/codegen/azure-text-analyis.json") 1934 require.NoError(t, err) 1935 1936 definitions := specDoc.Spec().Definitions 1937 k := "OperationResult" 1938 opts := opts() 1939 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1940 require.NoError(t, err) 1941 1942 buf := bytes.NewBuffer(nil) 1943 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1944 1945 ct, err := opts.LanguageOpts.FormatContent("out_obj.go", buf.Bytes()) 1946 require.NoError(t, err) 1947 1948 res := string(ct) 1949 assertInCode(t, `&& err != io.EOF`, res) 1950 } 1951 1952 func TestImports_ExistingModel(t *testing.T) { 1953 specDoc, err := loads.Spec("../fixtures/codegen/existing-model.yml") 1954 require.NoError(t, err) 1955 1956 definitions := specDoc.Spec().Definitions 1957 opts := opts() 1958 1959 k := "JsonWebKeySet" 1960 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1961 require.NoError(t, err) 1962 1963 require.NotNil(t, genModel) 1964 require.NotNil(t, genModel.Imports) 1965 assert.Equal(t, "github.com/user/package", genModel.Imports["jwk"]) 1966 1967 k = "JsonWebKey" 1968 genModel, err = makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1969 require.NoError(t, err) 1970 1971 require.NotNil(t, genModel) 1972 require.NotNil(t, genModel.Imports) 1973 assert.Equal(t, "github.com/user/package", genModel.Imports["jwk"]) 1974 } 1975 1976 func TestGenModel_Issue786(t *testing.T) { 1977 specDoc, err := loads.Spec("../fixtures/bugs/786/swagger.yml") 1978 require.NoError(t, err) 1979 1980 definitions := specDoc.Spec().Definitions 1981 k := "MyFirstObject" 1982 opts := opts() 1983 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 1984 require.NoError(t, err) 1985 1986 require.False(t, genModel.Properties[0].AdditionalProperties.IsNullable) 1987 1988 buf := bytes.NewBuffer(nil) 1989 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 1990 1991 ct, err := opts.LanguageOpts.FormatContent("MyFirstObject.go", buf.Bytes()) 1992 require.NoError(t, err) 1993 1994 res := string(ct) 1995 assertInCode(t, `m.validateEntreeChoiceValueEnum("entree_choice"+"."+k, "body", m.EntreeChoice[k])`, res) 1996 } 1997 1998 func TestGenModel_Issue822(t *testing.T) { 1999 specDoc, err := loads.Spec("../fixtures/bugs/822/swagger.yml") 2000 require.NoError(t, err) 2001 2002 definitions := specDoc.Spec().Definitions 2003 k := "Pet" 2004 opts := opts() 2005 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 2006 require.NoError(t, err) 2007 2008 ap := genModel.AdditionalProperties 2009 require.True(t, genModel.HasAdditionalProperties) 2010 require.NotNil(t, ap) 2011 require.False(t, ap.IsNullable) 2012 2013 buf := bytes.NewBuffer(nil) 2014 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2015 2016 ct, err := opts.LanguageOpts.FormatContent("pet.go", buf.Bytes()) 2017 require.NoError(t, err) 2018 2019 res := string(ct) 2020 assertInCode(t, `PetAdditionalProperties map[string]interface{}`, res) 2021 assertInCode(t, `m.PetAdditionalProperties = result`, res) 2022 assertInCode(t, `additional, err := json.Marshal(m.PetAdditionalProperties)`, res) 2023 } 2024 2025 func TestGenModel_Issue981(t *testing.T) { 2026 specDoc, err := loads.Spec("../fixtures/bugs/981/swagger.json") 2027 require.NoError(t, err) 2028 2029 definitions := specDoc.Spec().Definitions 2030 k := "User" 2031 opts := opts() 2032 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 2033 require.NoError(t, err) 2034 2035 buf := bytes.NewBuffer(nil) 2036 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2037 2038 ct, err := opts.LanguageOpts.FormatContent("user.go", buf.Bytes()) 2039 require.NoError(t, err) 2040 2041 res := string(ct) 2042 assertInCode(t, "FirstName string `json:\"first_name,omitempty\"`", res) 2043 assertInCode(t, "LastName string `json:\"last_name,omitempty\"`", res) 2044 assertInCode(t, "if swag.IsZero(m.Type)", res) 2045 assertInCode(t, `validate.MinimumInt("user_type", "body", m.Type, 1, false)`, res) 2046 assertInCode(t, `validate.MaximumInt("user_type", "body", m.Type, 5, false)`, res) 2047 } 2048 2049 func TestGenModel_Issue1341(t *testing.T) { 2050 specDoc, err := loads.Spec("../fixtures/bugs/1341/swagger.yaml") 2051 require.NoError(t, err) 2052 2053 definitions := specDoc.Spec().Definitions 2054 k := "ExecutableValueString" 2055 schema := definitions[k] 2056 opts := opts() 2057 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2058 require.NoError(t, err) 2059 2060 buf := bytes.NewBuffer(nil) 2061 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2062 2063 ff, err := opts.LanguageOpts.FormatContent("executable_value_string.go", buf.Bytes()) 2064 require.NoError(t, err) 2065 2066 res := string(ff) 2067 assertInCode(t, `return errors.New(422, "invalid ValueType value: %q", base.ValueType`, res) 2068 assertInCode(t, "result.testField = base.Test", res) 2069 assertInCode(t, "Test *string `json:\"Test\"`", res) 2070 assertInCode(t, "Test: m.Test(),", res) 2071 } 2072 2073 // This tests to check that format validation is performed on non required schema properties 2074 func TestGenModel_Issue1347(t *testing.T) { 2075 specDoc, err := loads.Spec("../fixtures/bugs/1347/fixture-1347.yaml") 2076 require.NoError(t, err) 2077 2078 definitions := specDoc.Spec().Definitions 2079 schema := definitions["ContainerConfig"] 2080 opts := opts() 2081 genModel, err := makeGenDefinition("ContainerConfig", "models", schema, specDoc, opts) 2082 require.NoError(t, err) 2083 2084 buf := bytes.NewBuffer(nil) 2085 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2086 2087 ff, err := opts.LanguageOpts.FormatContent("Foo.go", buf.Bytes()) 2088 require.NoError(t, err) 2089 2090 res := string(ff) 2091 // Just verify that the validation call is generated even though we add a non-required property 2092 assertInCode(t, `validate.FormatOf("config1", "body", "hostname", m.Config1.String(), formats)`, res) 2093 } 2094 2095 // This tests to check that format validation is performed on MAC format 2096 func TestGenModel_Issue1348(t *testing.T) { 2097 specDoc, err := loads.Spec("../fixtures/bugs/1348/fixture-1348.yaml") 2098 require.NoError(t, err) 2099 2100 definitions := specDoc.Spec().Definitions 2101 k := "ContainerConfig" 2102 schema := definitions[k] 2103 opts := opts() 2104 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2105 require.NoError(t, err) 2106 2107 buf := bytes.NewBuffer(nil) 2108 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2109 2110 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2111 require.NoError(t, err) 2112 2113 res := string(ct) 2114 // Just verify that the validation call is generated with proper format 2115 assertInCode(t, `if err := validate.FormatOf("config1", "body", "mac", m.Config1.String(), formats)`, res) 2116 } 2117 2118 // This tests that additionalProperties with validation is generated properly. 2119 func TestGenModel_Issue1198(t *testing.T) { 2120 specDoc, err := loads.Spec("../fixtures/bugs/1198/fixture-1198.yaml") 2121 require.NoError(t, err) 2122 2123 definitions := specDoc.Spec().Definitions 2124 k := "pet" 2125 schema := definitions[k] 2126 opts := opts() 2127 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2128 require.NoError(t, err) 2129 2130 buf := bytes.NewBuffer(nil) 2131 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2132 2133 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2134 require.NoError(t, err) 2135 2136 res := string(ct) 2137 // Just verify that the validation call is generated with proper format 2138 assertInCode(t, `if err := m.validateDate(formats); err != nil {`, res) 2139 } 2140 2141 // This tests that additionalProperties with validation is generated properly. 2142 func TestGenModel_Issue1397a(t *testing.T) { 2143 specDoc, err := loads.Spec("../fixtures/bugs/1397/fixture-1397a.yaml") 2144 require.NoError(t, err) 2145 2146 definitions := specDoc.Spec().Definitions 2147 k := "ContainerConfig" 2148 schema := definitions[k] 2149 opts := opts() 2150 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2151 require.NoError(t, err) 2152 2153 buf := bytes.NewBuffer(nil) 2154 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2155 2156 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2157 require.NoError(t, err) 2158 2159 res := string(ct) 2160 // Just verify that the validation call is generated with proper format 2161 assertInCode(t, `if swag.IsZero(m[k]) { // not required`, res) 2162 } 2163 2164 // This tests that an enum of object values validates properly. 2165 func TestGenModel_Issue1397b(t *testing.T) { 2166 specDoc, err := loads.Spec("../fixtures/bugs/1397/fixture-1397b.yaml") 2167 require.NoError(t, err) 2168 2169 definitions := specDoc.Spec().Definitions 2170 k := "ContainerConfig" 2171 schema := definitions[k] 2172 opts := opts() 2173 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2174 require.NoError(t, err) 2175 2176 buf := bytes.NewBuffer(nil) 2177 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2178 2179 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2180 require.NoError(t, err) 2181 2182 res := string(ct) 2183 // Just verify that the validation call is generated with proper format 2184 assertInCode(t, `if err := m.validateContainerConfigEnum("", "body", m); err != nil {`, res) 2185 } 2186 2187 // This tests that additionalProperties with an array of polymorphic objects is generated properly. 2188 func TestGenModel_Issue1409(t *testing.T) { 2189 specDoc, err := loads.Spec("../fixtures/bugs/1409/fixture-1409.yaml") 2190 require.NoError(t, err) 2191 2192 definitions := specDoc.Spec().Definitions 2193 k := "Graph" 2194 schema := definitions[k] 2195 opts := opts() 2196 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2197 require.NoError(t, err) 2198 2199 buf := bytes.NewBuffer(nil) 2200 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2201 2202 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2203 require.NoError(t, err) 2204 2205 res := string(ct) 2206 // Just verify that the validation call is generated with proper format 2207 assertInCode(t, `nodes, err := UnmarshalNodeSlice(bytes.NewBuffer(data.Nodes), runtime.JSONConsumer())`, res) 2208 assertInCode(t, `if err := json.Unmarshal(raw, &rawProps); err != nil {`, res) 2209 assertInCode(t, `m.GraphAdditionalProperties[k] = toadd`, res) 2210 assertInCode(t, `b3, err = json.Marshal(m.GraphAdditionalProperties)`, res) 2211 } 2212 2213 // This tests that a model with a discriminator doesn't validation if the field is zero. 2214 func TestGenModel_Issue2911(t *testing.T) { 2215 specDoc, err := loads.Spec("../fixtures/bugs/2911/fixture-2911.yaml") 2216 require.NoError(t, err) 2217 2218 definitions := specDoc.Spec().Definitions 2219 k := "animal" 2220 schema := definitions[k] 2221 opts := opts() 2222 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2223 require.NoError(t, err) 2224 2225 buf := bytes.NewBuffer(nil) 2226 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2227 2228 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2229 require.NoError(t, err) 2230 2231 res := string(ct) 2232 2233 // Just verify that the validation call is generated with proper format 2234 assertInCode(t, `func (m *Animal) contextValidateKind(ctx context.Context, formats strfmt.Registry) error { 2235 2236 if swag.IsZero(m.Kind()) { // not required 2237 return nil 2238 }`, res) 2239 } 2240 2241 // This tests makes sure model definitions from inline schema in response are properly flattened and get validation 2242 func TestGenModel_Issue866(t *testing.T) { 2243 defer discardOutput()() 2244 2245 specDoc, err := loads.Spec("../fixtures/bugs/866/fixture-866.yaml") 2246 require.NoError(t, err) 2247 2248 p, ok := specDoc.Spec().Paths.Paths["/"] 2249 require.True(t, ok) 2250 2251 op := p.Get 2252 responses := op.Responses.StatusCodeResponses 2253 for k, r := range responses { 2254 t.Logf("Response: %d", k) 2255 schema := *r.Schema 2256 opts := opts() 2257 genModel, err := makeGenDefinition("GetOKBody", "models", schema, specDoc, opts) 2258 require.NoError(t, err) 2259 2260 buf := bytes.NewBuffer(nil) 2261 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2262 2263 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2264 require.NoError(t, err) 2265 2266 res := string(ct) 2267 assertInCode(t, `if err := validate.Required(`, res) 2268 assertInCode(t, `if err := validate.MaxLength(`, res) 2269 assertInCode(t, `if err := m.validateAccessToken(formats); err != nil {`, res) 2270 assertInCode(t, `if err := m.validateAccountID(formats); err != nil {`, res) 2271 } 2272 } 2273 2274 // This tests makes sure marshalling and validation is generated in aliased formatted definitions 2275 func TestGenModel_Issue946(t *testing.T) { 2276 specDoc, err := loads.Spec("../fixtures/bugs/946/fixture-946.yaml") 2277 require.NoError(t, err) 2278 2279 definitions := specDoc.Spec().Definitions 2280 k := "mydate" 2281 schema := definitions[k] 2282 opts := opts() 2283 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2284 require.NoError(t, err) 2285 2286 buf := bytes.NewBuffer(nil) 2287 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2288 2289 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2290 require.NoError(t, err) 2291 2292 res := string(ct) 2293 assertInCode(t, `type Mydate strfmt.Date`, res) 2294 assertInCode(t, `func (m *Mydate) UnmarshalJSON(b []byte) error {`, res) 2295 assertInCode(t, `return ((*strfmt.Date)(m)).UnmarshalJSON(b)`, res) 2296 assertInCode(t, `func (m Mydate) MarshalJSON() ([]byte, error) {`, res) 2297 assertInCode(t, `return (strfmt.Date(m)).MarshalJSON()`, res) 2298 assertInCode(t, `if err := validate.FormatOf("", "body", "date", strfmt.Date(m).String(), formats); err != nil {`, res) 2299 } 2300 2301 // This tests makes sure that docstring in inline schema in response properly reflect the Required property 2302 func TestGenModel_Issue910(t *testing.T) { 2303 specDoc, err := loads.Spec("../fixtures/bugs/910/fixture-910.yaml") 2304 require.NoError(t, err) 2305 2306 p, ok := specDoc.Spec().Paths.Paths["/mytest"] 2307 require.True(t, ok) 2308 2309 op := p.Get 2310 responses := op.Responses.StatusCodeResponses 2311 for k, r := range responses { 2312 t.Logf("Response: %d", k) 2313 schema := *r.Schema 2314 opts := opts() 2315 genModel, err := makeGenDefinition("GetMyTestOKBody", "models", schema, specDoc, opts) 2316 require.NoError(t, err) 2317 2318 buf := bytes.NewBuffer(nil) 2319 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2320 2321 ct, err := opts.LanguageOpts.FormatContent("foo.go", buf.Bytes()) 2322 require.NoError(t, err) 2323 2324 res := string(ct) 2325 assertInCode(t, "// bar\n // Required: true\n Bar *int64 `json:\"bar\"`", res) 2326 assertInCode(t, "// foo\n // Required: true\n Foo interface{} `json:\"foo\"`", res) 2327 assertInCode(t, "// baz\n Baz int64 `json:\"baz,omitempty\"`", res) 2328 assertInCode(t, "// quux\n Quux []string `json:\"quux\"`", res) 2329 assertInCode(t, `if err := validate.Required("bar", "body", m.Bar); err != nil {`, res) 2330 assertInCode(t, `if m.Foo == nil {`, res) // interface{} now checked against nil (validate.Required fails on any zero value) 2331 assertNotInCode(t, `if err := validate.Required("baz", "body", m.Baz); err != nil {`, res) 2332 assertNotInCode(t, `if err := validate.Required("quux", "body", m.Quux); err != nil {`, res) 2333 // NOTE(fredbi); fixed Required in slices. This property has actually no validation 2334 } 2335 } 2336 2337 func TestGenerateModel_Xorder(t *testing.T) { 2338 specDoc, err := loads.Spec("../fixtures/codegen/x-order.yml") 2339 require.NoError(t, err) 2340 2341 definitions := specDoc.Spec().Definitions 2342 k := "sessionData" 2343 schema := definitions[k] 2344 opts := opts() 2345 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2346 require.NoError(t, err) 2347 2348 buf := bytes.NewBuffer(nil) 2349 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2350 2351 ff, err := opts.LanguageOpts.FormatContent("x-order.go", buf.Bytes()) 2352 require.NoError(t, err) 2353 2354 res := string(ff) 2355 // if no x-order then alphabetical order, like DeviceID, SessionID, UMain. 2356 // There is x-order 2357 // sessionId 2358 // x-order: 0 2359 // deviceId: 2360 // x-order: 1 2361 // uMain: 2362 // x-order: 2 2363 // This is need for msgpack-array. 2364 foundDeviceID := strings.Index(res, "DeviceID") 2365 foundSessionID := strings.Index(res, "SessionID") 2366 foundUMain := strings.Index(res, "UMain") 2367 foundAaa := strings.Index(res, "Aaa") 2368 foundBbb := strings.Index(res, "Bbb") 2369 foundZzz := strings.Index(res, "Zzz") 2370 assert.Less(t, foundSessionID, foundDeviceID) 2371 assert.Less(t, foundSessionID, foundUMain) 2372 assert.Less(t, foundUMain, foundAaa) 2373 assert.Less(t, foundAaa, foundBbb) 2374 assert.Less(t, foundBbb, foundZzz) 2375 } 2376 2377 func TestGenModel_Issue1623(t *testing.T) { 2378 specDoc, err := loads.Spec("../fixtures/enhancements/1623/swagger.yml") 2379 require.NoError(t, err) 2380 2381 definitions := specDoc.Spec().Definitions 2382 k := "Foo" 2383 schema := definitions[k] 2384 opts := opts() 2385 2386 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2387 require.NoError(t, err) 2388 2389 buf := bytes.NewBuffer(nil) 2390 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2391 2392 ff, err := opts.LanguageOpts.FormatContent("Foo.go", buf.Bytes()) 2393 require.NoError(t, err) 2394 2395 res := string(ff) 2396 assertInCode(t, "ArrayHasOmitEmptyFalse []string `json:\"arrayHasOmitEmptyFalse\"`", res) 2397 assertInCode(t, "ArrayHasOmitEmptyTrue []string `json:\"arrayHasOmitEmptyTrue,omitempty\"`", res) 2398 assertInCode(t, "ArrayNoOmitEmpty []string `json:\"arrayNoOmitEmpty\"`", res) 2399 assertInCode(t, "GeneralHasOmitEmptyFalse string `json:\"generalHasOmitEmptyFalse\"`", res) 2400 assertInCode(t, "GeneralHasOmitEmptyTrue string `json:\"generalHasOmitEmptyTrue,omitempty\"`", res) 2401 assertInCode(t, "GeneralNoOmitEmpty string `json:\"generalNoOmitEmpty,omitempty\"`", res) 2402 assertInCode(t, "RefHasOmitEmptyFalse Bar `json:\"refHasOmitEmptyFalse,omitempty\"`", res) 2403 assertInCode(t, "RefHasOmitEmptyTrue Bar `json:\"refHasOmitEmptyTrue,omitempty\"`", res) 2404 assertInCode(t, "RefNoOmitEmpty Bar `json:\"refNoOmitEmpty,omitempty\"`", res) 2405 assertInCode(t, "IntHasJSONString int64 `json:\"intHasJsonString,omitempty,string\"`", res) 2406 assertInCode(t, "BoolHasJSONString bool `json:\"boolHasJsonString,omitempty,string\"`", res) 2407 } 2408 2409 func TestGenerateModel_Issue2457(t *testing.T) { 2410 specDoc, err := loads.Spec("../fixtures/bugs/2457/fixture-2457.yaml") 2411 require.NoError(t, err) 2412 2413 definitions := specDoc.Spec().Definitions 2414 k := "ObjWithCustomTag" 2415 schema := definitions[k] 2416 opts := opts() 2417 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2418 require.NoError(t, err) 2419 2420 buf := bytes.NewBuffer(nil) 2421 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2422 2423 assertInCode(t, "myobjtag:\"foo,bar\"", buf.String()) 2424 } 2425 2426 func TestGenModel_Pr2464(t *testing.T) { 2427 specDoc, err := loads.Spec("../fixtures/enhancements/2464/fixture-2464.yaml") 2428 require.NoError(t, err) 2429 2430 definitions := specDoc.Spec().Definitions 2431 2432 tests := map[string]struct { 2433 model string 2434 expected []string 2435 }{ 2436 "withDot": { 2437 model: "band", 2438 expected: []string{ 2439 `BandNr2Dot4Ghz Band = "2.4Ghz"`, 2440 `BandNr24Ghz Band = "24Ghz"`, 2441 }, 2442 }, 2443 "withSigns": { 2444 model: "change", 2445 expected: []string{ 2446 `ChangeDash1 Change = "-1"`, 2447 `ChangeNr0 Change = "0"`, 2448 `ChangePlus1 Change = "+1"`, 2449 }, 2450 }, 2451 "hashtag": { 2452 model: "topic", 2453 expected: []string{ 2454 `TopicHashtagOne Topic = "#one"`, 2455 `TopicTwoHashtagTwo Topic = "two#two"`, 2456 }, 2457 }, 2458 } 2459 2460 for name, spec := range tests { 2461 t.Run(name, func(t *testing.T) { 2462 k := spec.model 2463 schema := definitions[k] 2464 opts := opts() 2465 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2466 require.NoError(t, err) 2467 2468 buf := bytes.NewBuffer(nil) 2469 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2470 2471 for _, expected := range spec.expected { 2472 assertInCode(t, expected, buf.String()) 2473 } 2474 }) 2475 } 2476 } 2477 2478 func TestGenModel_KeepSpecPropertiesOrder(t *testing.T) { 2479 ymlFile := "../fixtures/codegen/keep-spec-order.yml" 2480 opts := opts() 2481 abcType := "abctype" 2482 2483 specDoc, err := loads.Spec(ymlFile) 2484 require.NoError(t, err) 2485 2486 orderedSpecDoc, err := loads.Spec(WithAutoXOrder(ymlFile)) 2487 require.NoError(t, err) 2488 2489 definitions := specDoc.Spec().Definitions 2490 orderedDefinitions := orderedSpecDoc.Spec().Definitions 2491 2492 genModel, err := makeGenDefinition(abcType, "models", definitions[abcType], specDoc, opts) 2493 require.NoError(t, err) 2494 orderGenModel, err := makeGenDefinition(abcType, "models", orderedDefinitions[abcType], orderedSpecDoc, opts) 2495 require.NoError(t, err) 2496 2497 buf := bytes.NewBuffer(nil) 2498 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2499 2500 orderBuf := bytes.NewBuffer(nil) 2501 require.NoError(t, opts.templates.MustGet("model").Execute(orderBuf, orderGenModel)) 2502 2503 ff, err := opts.LanguageOpts.FormatContent("keepSpecOrder.go", buf.Bytes()) 2504 require.NoError(t, err) 2505 2506 modelCode := string(ff) 2507 ff, err = opts.LanguageOpts.FormatContent("keepSpecOrder-ordered.go", orderBuf.Bytes()) 2508 require.NoError(t, err) 2509 2510 orderModelCode := string(ff) 2511 2512 // without auto order, properties sorted by alphanumeric 2513 foundA := strings.Index(modelCode, "Aaa") 2514 foundB := strings.Index(modelCode, "Bbb") 2515 foundC := strings.Index(modelCode, "Ccc") 2516 assert.Less(t, foundA, foundB) 2517 assert.Less(t, foundB, foundC) 2518 2519 foundOrderA := strings.Index(orderModelCode, "Aaa") 2520 foundOrderB := strings.Index(orderModelCode, "Bbb") 2521 foundOrderC := strings.Index(orderModelCode, "Ccc") 2522 2523 assert.Less(t, foundOrderC, foundOrderB) 2524 assert.Less(t, foundOrderB, foundOrderA) 2525 2526 foundInnerA := strings.Index(modelCode, "InnerAaa") 2527 foundInnerB := strings.Index(modelCode, "InnerBbb") 2528 foundInnerC := strings.Index(modelCode, "InnerCcc") 2529 assert.Less(t, foundInnerA, foundInnerB) 2530 assert.Less(t, foundInnerB, foundInnerC) 2531 2532 foundOrderInnerA := strings.Index(orderModelCode, "InnerAaa") 2533 foundOrderInnerB := strings.Index(orderModelCode, "InnerBbb") 2534 foundOrderInnerC := strings.Index(orderModelCode, "InnerCcc") 2535 2536 assert.Less(t, foundOrderInnerC, foundOrderInnerB) 2537 assert.Less(t, foundOrderInnerB, foundOrderInnerA) 2538 } 2539 2540 func TestGenModel_StrictAdditionalProperties(t *testing.T) { 2541 specDoc, err := loads.Spec("../fixtures/codegen/strict-additional-properties.yml") 2542 require.NoError(t, err) 2543 2544 definitions := specDoc.Spec().Definitions 2545 k := "Body" 2546 schema := definitions[k] 2547 opts := opts() 2548 2549 opts.StrictAdditionalProperties = true 2550 2551 genModel, err := makeGenDefinition(k, "models", schema, specDoc, opts) 2552 require.NoError(t, err) 2553 2554 buf := bytes.NewBuffer(nil) 2555 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2556 2557 ff, err := opts.LanguageOpts.FormatContent("strictAdditionalProperties.go", buf.Bytes()) 2558 require.NoError(t, err) 2559 2560 res := string(ff) 2561 for _, tt := range []struct { 2562 name string 2563 assertion func(testing.TB, string, string) bool 2564 }{ 2565 {k, assertInCode}, 2566 {k + "Explicit", assertInCode}, 2567 {k + "Implicit", assertInCode}, 2568 {k + "Disabled", assertNotInCode}, 2569 } { 2570 fn := funcBody(res, "*"+tt.name+") UnmarshalJSON(data []byte) error") 2571 if assert.NotEmpty(t, fn, "Method UnmarshalJSON should be defined for type *"+tt.name) { 2572 tt.assertion(t, "dec.DisallowUnknownFields()", fn) 2573 } 2574 } 2575 } 2576 2577 func TestGenModel_XMLStructTags_WithXML(t *testing.T) { 2578 specDoc, err := loads.Spec("../fixtures/codegen/xml-model.yml") 2579 require.NoError(t, err) 2580 2581 definitions := specDoc.Spec().Definitions 2582 k := "XmlWithAttribute" 2583 opts := opts() 2584 opts.WithXML = true 2585 2586 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 2587 require.NoError(t, err) 2588 2589 buf := bytes.NewBuffer(nil) 2590 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2591 2592 ct, err := opts.LanguageOpts.FormatContent("xml_with_attribute.go", buf.Bytes()) 2593 require.NoError(t, err) 2594 2595 res := string(ct) 2596 assertInCode(t, "Author *string `json:\"author\" xml:\"author\"`", res) 2597 assertInCode(t, "Children []*XMLChild `json:\"children\" xml:\"children\"`", res) 2598 assertInCode(t, "ID int64 `json:\"id,omitempty\" xml:\"id,attr,omitempty\"`", res) 2599 assertInCode(t, "IsPublished *bool `json:\"isPublished\" xml:\"published,attr\"`", res) 2600 assertInCode(t, "SingleChild *XMLChild `json:\"singleChild,omitempty\" xml:\"singleChild,omitempty\"`", res) 2601 assertInCode(t, "Title string `json:\"title,omitempty\" xml:\"xml-title,omitempty\"`", res) 2602 } 2603 2604 func TestGenModel_XMLStructTags_Explicit(t *testing.T) { 2605 specDoc, err := loads.Spec("../fixtures/codegen/xml-model.yml") 2606 require.NoError(t, err) 2607 2608 definitions := specDoc.Spec().Definitions 2609 k := "XmlWithAttribute" 2610 opts := opts() 2611 2612 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 2613 require.NoError(t, err) 2614 2615 buf := bytes.NewBuffer(nil) 2616 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2617 2618 ct, err := opts.LanguageOpts.FormatContent("xml_with_attribute.go", buf.Bytes()) 2619 require.NoErrorf(t, err, "format error: %v\n%s", err, buf.String()) 2620 2621 res := string(ct) 2622 assertInCode(t, "Author *string `json:\"author\"`", res) 2623 assertInCode(t, "Children []*XMLChild `json:\"children\"`", res) 2624 assertInCode(t, "ID int64 `json:\"id,omitempty\" xml:\"id,attr,omitempty\"`", res) 2625 assertInCode(t, "IsPublished *bool `json:\"isPublished\" xml:\"published,attr\"`", res) 2626 assertInCode(t, "SingleChild *XMLChild `json:\"singleChild,omitempty\"`", res) 2627 assertInCode(t, "Title string `json:\"title,omitempty\" xml:\"xml-title,omitempty\"`", res) 2628 } 2629 2630 func TestGenerateModels(t *testing.T) { 2631 t.Parallel() 2632 defer discardOutput()() 2633 2634 cwd := testCwd(t) 2635 const root = "generated_models" 2636 defer func() { 2637 _ = os.RemoveAll(filepath.Join(cwd, root)) 2638 }() 2639 2640 t.Run("generate models", func(t *testing.T) { 2641 cases := map[string]generateFixture{ 2642 "allDefinitions": { 2643 spec: "../fixtures/bugs/1042/fixture-1042.yaml", 2644 target: "../fixtures/bugs/1042", 2645 verify: func(t *testing.T, target string) { 2646 target = filepath.Join(target, defaultModelsTarget) 2647 require.True(t, fileExists(target, "")) 2648 assert.True(t, fileExists(target, "a.go")) 2649 assert.True(t, fileExists(target, "b.go")) 2650 }, 2651 }, 2652 "acceptDefinitions": { 2653 spec: "../fixtures/enhancements/2333/fixture-definitions.yaml", 2654 target: "../fixtures/enhancements/2333", 2655 prepare: func(_ *testing.T, opts *GenOpts) { 2656 opts.AcceptDefinitionsOnly = true 2657 }, 2658 verify: func(t *testing.T, target string) { 2659 target = filepath.Join(target, defaultModelsTarget) 2660 require.True(t, fileExists(target, "")) 2661 assert.True(t, fileExists(target, "model_interface.go")) 2662 assert.True(t, fileExists(target, "records_model.go")) 2663 assert.True(t, fileExists(target, "records_model_with_max.go")) 2664 assert.False(t, fileExists(target, "restapi")) 2665 }, 2666 }, 2667 "mangleNames": { 2668 spec: "../fixtures/bugs/2821/ServiceManagementBody.json", 2669 target: "../fixtures/bugs/2821", 2670 verify: func(t *testing.T, target string) { 2671 target = filepath.Join(target, defaultModelsTarget) 2672 require.True(t, fileExists(target, "schema.go")) 2673 content, err := os.ReadFile(filepath.Join(target, "schema.go")) 2674 require.NoError(t, err) 2675 assert.Contains(t, string(content), "getDollarRefField string") 2676 }, 2677 }, 2678 } 2679 for k, cas := range cases { 2680 name := k 2681 thisCas := cas 2682 2683 t.Run(name, func(t *testing.T) { 2684 t.Parallel() 2685 2686 defer thisCas.warnFailed(t) 2687 2688 opts := testGenOpts() 2689 defer thisCas.prepareTarget(t, name, "model_test", root, opts)() 2690 2691 if thisCas.prepare != nil { 2692 thisCas.prepare(t, opts) 2693 } 2694 2695 t.Run(fmt.Sprintf("generating test models from: %s", opts.Spec), func(t *testing.T) { 2696 err := GenerateModels([]string{"", ""}, opts) // NOTE: generate all models, ignore "" 2697 if thisCas.wantError { 2698 require.Errorf(t, err, "expected an error for models build fixture: %s", opts.Spec) 2699 } else { 2700 require.NoError(t, err, "unexpected error for models build fixture: %s", opts.Spec) 2701 } 2702 2703 if thisCas.verify != nil { 2704 thisCas.verify(t, opts.Target) 2705 } 2706 }) 2707 }) 2708 } 2709 }) 2710 } 2711 2712 func Test_PointerConversions(t *testing.T) { 2713 // generation of a pointer converter for enum vars 2714 specDoc, err := loads.Spec("../fixtures/bugs/252/swagger.json") 2715 require.NoError(t, err) 2716 2717 definitions := specDoc.Spec().Definitions 2718 k := "SodaBrand" 2719 opts := opts() 2720 genModel, err := makeGenDefinition(k, "models", definitions[k], specDoc, opts) 2721 require.NoError(t, err) 2722 require.False(t, genModel.IsNullable) 2723 2724 buf := bytes.NewBuffer(nil) 2725 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2726 2727 ct, err := opts.LanguageOpts.FormatContent("soda_brand.go", buf.Bytes()) 2728 require.NoError(t, err) 2729 2730 res := string(ct) 2731 funcLines := [][]string{ 2732 { 2733 "func NewSodaBrand(value SodaBrand) *SodaBrand {", 2734 "\treturn &value", 2735 "}", 2736 }, 2737 { 2738 "func (m SodaBrand) Pointer() *SodaBrand {", 2739 "\treturn &m", 2740 "}", 2741 }, 2742 } 2743 for _, f := range funcLines { 2744 joined := strings.Join(f, "\n") 2745 assert.Contains(t, res, joined) 2746 } 2747 } 2748 2749 func TestIssue2597(t *testing.T) { 2750 specDoc, err := loads.Spec("../fixtures/bugs/2597/2597.yaml") 2751 require.NoError(t, err) 2752 2753 const antipattern = `(validate\.\w+\("",\s+"body",.+?\))|(errors\.\w+\("",\s+"body",.+?\))` 2754 definitions := specDoc.Spec().Definitions 2755 2756 t.Run("with RootedErrorPath option", func(t *testing.T) { 2757 opts := opts() 2758 opts.WantsRootedErrorPath = true 2759 2760 t.Run("should generate the extra path for arrays and maps", func(t *testing.T) { 2761 for _, model := range []string{ 2762 "BlahArray", 2763 "BlahComplexArray", 2764 "BlahMap", 2765 "BlahComplexMap", 2766 } { 2767 pattern := fmt.Sprintf(`(validate\.\w+\("\[%[1]s\]",\s+"body",.+?\))|(errors\.\w+\("\[%[1]s\]",\s+"body",.+?\))`, model) 2768 genModel, err := makeGenDefinition(model, "models", definitions[model], specDoc, opts) 2769 require.NoError(t, err) 2770 2771 buf := bytes.NewBuffer(nil) 2772 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2773 2774 ct, err := opts.LanguageOpts.FormatContent("model.go", buf.Bytes()) 2775 require.NoErrorf(t, err, "format error: %v\n%s", err, buf.String()) 2776 2777 res := string(ct) 2778 assertRegexpInCode(t, pattern, res) 2779 assertRegexpNotInCode(t, antipattern, res) 2780 } 2781 }) 2782 2783 t.Run("should NOT generate the extra path for structs", func(t *testing.T) { 2784 const model = "BlahStruct" 2785 pattern := fmt.Sprintf(`(validate\.\w+\("\[%[1]s\]",\s+"body",.+?\))|(errors\.\w+\("\[%[1]s\]",\s+"body",.+?\))`, model) 2786 2787 genModel, err := makeGenDefinition(model, "models", definitions[model], specDoc, opts) 2788 require.NoError(t, err) 2789 2790 buf := bytes.NewBuffer(nil) 2791 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2792 2793 ct, err := opts.LanguageOpts.FormatContent("model.go", buf.Bytes()) 2794 require.NoErrorf(t, err, "format error: %v\n%s", err, buf.String()) 2795 2796 res := string(ct) 2797 assertRegexpNotInCode(t, pattern, res) 2798 assertRegexpNotInCode(t, antipattern, res) // we have a path, that is the property name 2799 }) 2800 }) 2801 2802 t.Run("without RootedErrorPath option", func(t *testing.T) { 2803 opts := opts() 2804 2805 t.Run("should NOT generate the extra path for arrays and maps", func(t *testing.T) { 2806 for _, model := range []string{ 2807 "BlahArray", 2808 "BlahComplexArray", 2809 "BlahMap", 2810 "BlahComplexMap", 2811 } { 2812 pattern := fmt.Sprintf(`(validate\.\w+\("\[%[1]s\]",\s+"body",.+?\))|(errors\.\w+\("\[%[1]s\]",\s+"body",.+?\))`, model) 2813 genModel, err := makeGenDefinition(model, "models", definitions[model], specDoc, opts) 2814 require.NoError(t, err) 2815 2816 buf := bytes.NewBuffer(nil) 2817 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2818 2819 ct, err := opts.LanguageOpts.FormatContent("model.go", buf.Bytes()) 2820 require.NoErrorf(t, err, "format error: %v\n%s", err, buf.String()) 2821 2822 res := string(ct) 2823 assertRegexpNotInCode(t, pattern, res) 2824 assertRegexpInCode(t, antipattern, res) 2825 } 2826 }) 2827 2828 t.Run("should NOT generate the extra path for structs", func(t *testing.T) { 2829 const model = "BlahStruct" 2830 pattern := fmt.Sprintf(`(validate\.\w+\("\[%[1]s\]",\s+"body",.+?\))|(errors\.\w+\("\[%[1]s\]",\s+"body",.+?\))`, model) 2831 2832 genModel, err := makeGenDefinition(model, "models", definitions[model], specDoc, opts) 2833 require.NoError(t, err) 2834 2835 buf := bytes.NewBuffer(nil) 2836 require.NoError(t, opts.templates.MustGet("model").Execute(buf, genModel)) 2837 2838 ct, err := opts.LanguageOpts.FormatContent("model.go", buf.Bytes()) 2839 require.NoErrorf(t, err, "format error: %v\n%s", err, buf.String()) 2840 2841 res := string(ct) 2842 assertRegexpNotInCode(t, pattern, res) 2843 assertRegexpNotInCode(t, antipattern, res) // we have a path, that is the property name 2844 }) 2845 }) 2846 }