github.com/emreu/go-swagger@v0.22.1/generator/operation_test.go (about) 1 // Copyright 2015 go-swagger maintainers 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package generator 16 17 import ( 18 "bytes" 19 "errors" 20 "fmt" 21 "io/ioutil" 22 "log" 23 "os" 24 "path/filepath" 25 "testing" 26 27 "github.com/go-openapi/analysis" 28 "github.com/go-openapi/loads" 29 "github.com/go-openapi/spec" 30 "github.com/stretchr/testify/assert" 31 ) 32 33 func TestUniqueOperationNames(t *testing.T) { 34 doc, err := loads.Spec("../fixtures/codegen/todolist.simple.yml") 35 if assert.NoError(t, err) { 36 sp := doc.Spec() 37 sp.Paths.Paths["/tasks"].Post.ID = "saveTask" 38 sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask") 39 sp.Paths.Paths["/tasks/{id}"].Put.ID = "saveTask" 40 sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask") 41 analyzed := analysis.New(sp) 42 43 ops := gatherOperations(analyzed, nil) 44 assert.Len(t, ops, 6) 45 _, exists := ops["saveTask"] 46 assert.True(t, exists) 47 _, exists = ops["PutTasksID"] 48 assert.True(t, exists) 49 } 50 } 51 52 func TestEmptyOperationNames(t *testing.T) { 53 doc, err := loads.Spec("../fixtures/codegen/todolist.simple.yml") 54 if assert.NoError(t, err) { 55 sp := doc.Spec() 56 sp.Paths.Paths["/tasks"].Post.ID = "" 57 sp.Paths.Paths["/tasks"].Post.AddExtension("origName", "createTask") 58 sp.Paths.Paths["/tasks/{id}"].Put.ID = "" 59 sp.Paths.Paths["/tasks/{id}"].Put.AddExtension("origName", "updateTask") 60 analyzed := analysis.New(sp) 61 62 ops := gatherOperations(analyzed, nil) 63 assert.Len(t, ops, 6) 64 _, exists := ops["PostTasks"] 65 assert.True(t, exists) 66 _, exists = ops["PutTasksID"] 67 assert.True(t, exists) 68 } 69 } 70 71 func TestMakeResponseHeader(t *testing.T) { 72 b, err := opBuilder("getTasks", "") 73 if assert.NoError(t, err) { 74 hdr := findResponseHeader(&b.Operation, 200, "X-Rate-Limit") 75 gh, er := b.MakeHeader("a", "X-Rate-Limit", *hdr) 76 if assert.NoError(t, er) { 77 assert.True(t, gh.IsPrimitive) 78 assert.Equal(t, "int32", gh.GoType) 79 assert.Equal(t, "X-Rate-Limit", gh.Name) 80 } 81 } 82 } 83 84 func TestMakeResponseHeaderDefaultValues(t *testing.T) { 85 b, err := opBuilder("getTasks", "") 86 if assert.NoError(t, err) { 87 var testCases = []struct { 88 name string // input 89 typeStr string // expected type 90 defaultValue interface{} // expected result 91 }{ 92 {"Access-Control-Allow-Origin", "string", "*"}, 93 {"X-Rate-Limit", "int32", nil}, 94 {"X-Rate-Limit-Remaining", "int32", float64(42)}, 95 {"X-Rate-Limit-Reset", "int32", "1449875311"}, 96 {"X-Rate-Limit-Reset-Human", "string", "3 days"}, 97 {"X-Rate-Limit-Reset-Human-Number", "string", float64(3)}, 98 } 99 100 for _, tc := range testCases { 101 // t.Logf("tc: %+v", tc) 102 hdr := findResponseHeader(&b.Operation, 200, tc.name) 103 assert.NotNil(t, hdr) 104 gh, er := b.MakeHeader("a", tc.name, *hdr) 105 if assert.NoError(t, er) { 106 assert.True(t, gh.IsPrimitive) 107 assert.Equal(t, tc.typeStr, gh.GoType) 108 assert.Equal(t, tc.name, gh.Name) 109 assert.Exactly(t, tc.defaultValue, gh.Default) 110 } 111 } 112 } 113 } 114 115 func TestMakeResponse(t *testing.T) { 116 b, err := opBuilder("getTasks", "") 117 if assert.NoError(t, err) { 118 resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc} 119 resolver.KnownDefs = make(map[string]struct{}) 120 for k := range b.Doc.Spec().Definitions { 121 resolver.KnownDefs[k] = struct{}{} 122 } 123 gO, err := b.MakeResponse("a", "getTasksSuccess", true, resolver, 200, b.Operation.Responses.StatusCodeResponses[200]) 124 if assert.NoError(t, err) { 125 assert.Len(t, gO.Headers, 6) 126 assert.NotNil(t, gO.Schema) 127 assert.True(t, gO.Schema.IsArray) 128 assert.NotNil(t, gO.Schema.Items) 129 assert.False(t, gO.Schema.IsAnonymous) 130 assert.Equal(t, "[]*models.Task", gO.Schema.GoType) 131 } 132 } 133 } 134 135 func TestMakeResponse_WithAllOfSchema(t *testing.T) { 136 b, err := methodPathOpBuilder("get", "/media/search", "../fixtures/codegen/instagram.yml") 137 if assert.NoError(t, err) { 138 resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc} 139 resolver.KnownDefs = make(map[string]struct{}) 140 for k := range b.Doc.Spec().Definitions { 141 resolver.KnownDefs[k] = struct{}{} 142 } 143 gO, err := b.MakeResponse("a", "get /media/search", true, resolver, 200, b.Operation.Responses.StatusCodeResponses[200]) 144 if assert.NoError(t, err) { 145 if assert.NotNil(t, gO.Schema) { 146 assert.Equal(t, "GetMediaSearchBody", gO.Schema.GoType) 147 } 148 if assert.NotEmpty(t, b.ExtraSchemas) { 149 body := b.ExtraSchemas["GetMediaSearchBody"] 150 if assert.NotEmpty(t, body.Properties) { 151 prop := body.Properties[0] 152 assert.Equal(t, "data", prop.Name) 153 // is in models only when definition is flattened: otherwise, ExtraSchema is rendered in operations package 154 assert.Equal(t, "[]*DataItems0", prop.GoType) 155 } 156 items := b.ExtraSchemas["DataItems0"] 157 if assert.NotEmpty(t, items.AllOf) { 158 media := items.AllOf[0] 159 // expect #definitions/media to be captured and reused by ExtraSchema 160 assert.Equal(t, "models.Media", media.GoType) 161 } 162 } 163 } 164 } 165 } 166 167 func TestMakeOperationParam(t *testing.T) { 168 b, err := opBuilder("getTasks", "") 169 if assert.NoError(t, err) { 170 resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc} 171 gO, err := b.MakeParameter("a", resolver, b.Operation.Parameters[0], nil) 172 if assert.NoError(t, err) { 173 assert.Equal(t, "size", gO.Name) 174 assert.True(t, gO.IsPrimitive) 175 } 176 } 177 } 178 179 func TestMakeOperationParamItem(t *testing.T) { 180 b, err := opBuilder("arrayQueryParams", "../fixtures/codegen/todolist.arrayquery.yml") 181 if assert.NoError(t, err) { 182 resolver := &typeResolver{ModelsPackage: b.ModelsPackage, Doc: b.Doc} 183 gO, err := b.MakeParameterItem("a", "siString", "ii", "siString", "a.SiString", "query", resolver, b.Operation.Parameters[1].Items, nil) 184 if assert.NoError(t, err) { 185 assert.Nil(t, gO.Parent) 186 assert.True(t, gO.IsPrimitive) 187 } 188 } 189 } 190 191 func TestMakeOperation(t *testing.T) { 192 b, err := opBuilder("getTasks", "") 193 if assert.NoError(t, err) { 194 gO, err := b.MakeOperation() 195 if assert.NoError(t, err) { 196 assert.Equal(t, "getTasks", gO.Name) 197 assert.Equal(t, "GET", gO.Method) 198 assert.Equal(t, "/tasks", gO.Path) 199 assert.Len(t, gO.Params, 2) 200 assert.Len(t, gO.Responses, 1) 201 assert.NotNil(t, gO.DefaultResponse) 202 assert.NotNil(t, gO.SuccessResponse) 203 } 204 } 205 } 206 207 func TestRenderOperation_InstagramSearch(t *testing.T) { 208 log.SetOutput(ioutil.Discard) 209 defer log.SetOutput(os.Stdout) 210 211 b, err := methodPathOpBuilder("get", "/media/search", "../fixtures/codegen/instagram.yml") 212 if assert.NoError(t, err) { 213 gO, ero := b.MakeOperation() 214 if assert.NoError(t, ero) { 215 buf := bytes.NewBuffer(nil) 216 opts := opts() 217 ert := templates.MustGet("serverOperation").Execute(buf, gO) 218 if assert.NoError(t, ert) { 219 ff, erf := opts.LanguageOpts.FormatContent("operation.go", buf.Bytes()) 220 if assert.NoError(t, erf) { 221 res := string(ff) 222 assertInCode(t, "type GetMediaSearchOKBody struct {", res) 223 // codegen does not assumes objects are only in models 224 // this is inlined 225 assertInCode(t, "Data []*DataItems0 `json:\"data\"`", res) 226 assertInCode(t, "type DataItems0 struct {", res) 227 // this is a definition: expect this definition to be reused from the models pkg 228 assertInCode(t, "models.Media", res) 229 } else { 230 fmt.Println(buf.String()) 231 t.FailNow() 232 } 233 } else { 234 t.FailNow() 235 } 236 237 buf = bytes.NewBuffer(nil) 238 ert = templates.MustGet("serverResponses").Execute(buf, gO) 239 if assert.NoError(t, ert) { 240 ff, erf := opts.LanguageOpts.FormatContent("response.go", buf.Bytes()) 241 if assert.NoError(t, erf) { 242 res := string(ff) 243 // codegen does not assumes objects are only in models 244 assertInCode(t, "type GetMediaSearchOK struct {", res) 245 assertInCode(t, "GetMediaSearchOKBody", res) 246 } else { 247 fmt.Println(buf.String()) 248 t.FailNow() 249 } 250 } else { 251 t.FailNow() 252 } 253 } 254 } 255 b, err = methodPathOpBuilderWithFlatten("get", "/media/search", "../fixtures/codegen/instagram.yml") 256 if assert.NoError(t, err) { 257 gO, ero := b.MakeOperation() 258 if assert.NoError(t, ero) { 259 buf := bytes.NewBuffer(nil) 260 opts := opts() 261 ert := templates.MustGet("serverOperation").Execute(buf, gO) 262 if assert.NoError(t, ert) { 263 ff, erf := opts.LanguageOpts.FormatContent("operation.go", buf.Bytes()) 264 if assert.NoError(t, erf) { 265 res := string(ff) 266 assertNotInCode(t, "DataItems0", res) 267 assertNotInCode(t, "models", res) 268 } else { 269 fmt.Println(buf.String()) 270 t.FailNow() 271 } 272 } else { 273 t.FailNow() 274 } 275 buf = bytes.NewBuffer(nil) 276 ert = templates.MustGet("serverResponses").Execute(buf, gO) 277 if assert.NoError(t, ert) { 278 ff, erf := opts.LanguageOpts.FormatContent("operation.go", buf.Bytes()) 279 if assert.NoError(t, erf) { 280 res := string(ff) 281 assertInCode(t, "Payload *models.GetMediaSearchOKBody", res) 282 } else { 283 fmt.Println(buf.String()) 284 } 285 } 286 } 287 } 288 } 289 290 func methodPathOpBuilder(method, path, fname string) (codeGenOpBuilder, error) { 291 if fname == "" { 292 fname = "../fixtures/codegen/todolist.simple.yml" 293 } 294 295 specDoc, err := loads.Spec(fname) 296 if err != nil { 297 return codeGenOpBuilder{}, err 298 } 299 300 analyzed := analysis.New(specDoc.Spec()) 301 op, ok := analyzed.OperationFor(method, path) 302 if !ok { 303 return codeGenOpBuilder{}, errors.New("No operation could be found for " + method + " " + path) 304 } 305 306 return codeGenOpBuilder{ 307 Name: method + " " + path, 308 Method: method, 309 Path: path, 310 APIPackage: "restapi", 311 ModelsPackage: "models", 312 Principal: "models.User", 313 Target: ".", 314 Operation: *op, 315 Doc: specDoc, 316 Analyzed: analyzed, 317 Authed: false, 318 ExtraSchemas: make(map[string]GenSchema), 319 GenOpts: opts(), 320 }, nil 321 } 322 323 // methodPathOpBuilderWithFlatten prepares an operation build based on method and path, with spec full flattening 324 func methodPathOpBuilderWithFlatten(method, path, fname string) (codeGenOpBuilder, error) { 325 if fname == "" { 326 fname = "../fixtures/codegen/todolist.simple.yml" 327 } 328 329 specDoc, err := loads.Spec(fname) 330 if err != nil { 331 return codeGenOpBuilder{}, err 332 } 333 334 o := opBuildGetOpts(fname, true, false) // flatten: true, minimal: false 335 336 specDoc, err = validateAndFlattenSpec(o, specDoc) 337 if err != nil { 338 return codeGenOpBuilder{}, err 339 } 340 341 analyzed := analysis.New(specDoc.Spec()) 342 op, ok := analyzed.OperationFor(method, path) 343 if !ok { 344 return codeGenOpBuilder{}, errors.New("No operation could be found for " + method + " " + path) 345 } 346 347 return codeGenOpBuilder{ 348 Name: method + " " + path, 349 Method: method, 350 Path: path, 351 APIPackage: "restapi", 352 ModelsPackage: "models", 353 Principal: "models.User", 354 Target: ".", 355 Operation: *op, 356 Doc: specDoc, 357 Analyzed: analyzed, 358 Authed: false, 359 ExtraSchemas: make(map[string]GenSchema), 360 GenOpts: opts(), 361 }, nil 362 } 363 364 // opBuilderWithOpts prepares the making of an operation with spec flattening options 365 func opBuilderWithOpts(name, fname string, o *GenOpts) (codeGenOpBuilder, error) { 366 if fname == "" { 367 // default fixture 368 fname = "../fixtures/codegen/todolist.simple.yml" 369 } 370 371 if !filepath.IsAbs(fname) { 372 cwd, _ := os.Getwd() 373 fname = filepath.Join(cwd, fname) 374 } 375 376 specDoc, err := loads.Spec(fname) 377 if err != nil { 378 return codeGenOpBuilder{}, err 379 } 380 o.Spec = fname 381 382 log.SetOutput(ioutil.Discard) 383 defer log.SetOutput(os.Stdout) 384 specDoc, err = validateAndFlattenSpec(o, specDoc) 385 if err != nil { 386 return codeGenOpBuilder{}, err 387 } 388 log.SetOutput(os.Stdout) 389 390 analyzed := analysis.New(specDoc.Spec()) 391 392 method, path, op, ok := analyzed.OperationForName(name) 393 if !ok { 394 return codeGenOpBuilder{}, errors.New("No operation could be found for " + name) 395 } 396 397 return codeGenOpBuilder{ 398 Name: name, 399 Method: method, 400 Path: path, 401 BasePath: specDoc.BasePath(), 402 APIPackage: "restapi", 403 ModelsPackage: "models", 404 Principal: "models.User", 405 Target: ".", 406 Operation: *op, 407 Doc: specDoc, 408 Analyzed: analyzed, 409 Authed: false, 410 ExtraSchemas: make(map[string]GenSchema), 411 GenOpts: o, // opts()?? 412 }, nil 413 } 414 415 func opBuildGetOpts(specName string, withFlatten bool, withMinimalFlatten bool) (opts *GenOpts) { 416 opts = &GenOpts{} 417 if erd := opts.EnsureDefaults(); erd != nil { 418 panic("Cannot initialize GenOpts") 419 } 420 opts.ValidateSpec = true 421 opts.FlattenOpts.Expand = !withFlatten 422 opts.FlattenOpts.Minimal = withMinimalFlatten 423 opts.Spec = specName 424 return 425 } 426 427 // opBuilderWithFlatten prepares the making of an operation with spec full flattening prior to rendering 428 func opBuilderWithFlatten(name, fname string) (codeGenOpBuilder, error) { 429 o := opBuildGetOpts(fname, true, false) // flatten: true, minimal: false 430 return opBuilderWithOpts(name, fname, o) 431 } 432 433 // opBuilderWithExpand prepares the making of an operation with spec expansion prior to rendering 434 func opBuilderWithExpand(name, fname string) (codeGenOpBuilder, error) { 435 o := opBuildGetOpts(fname, false, false) // flatten: false => expand 436 return opBuilderWithOpts(name, fname, o) 437 } 438 439 // opBuilder prepares the making of an operation with spec minimal flattening (default for CLI) 440 func opBuilder(name, fname string) (codeGenOpBuilder, error) { 441 o := opBuildGetOpts(fname, true, true) // flatten:true, minimal: true 442 // some fixtures do not fully validate - skip this 443 o.ValidateSpec = false 444 return opBuilderWithOpts(name, fname, o) 445 } 446 447 func findResponseHeader(op *spec.Operation, code int, name string) *spec.Header { 448 resp := op.Responses.Default 449 if code > 0 { 450 bb, ok := op.Responses.StatusCodeResponses[code] 451 if ok { 452 resp = &bb 453 } 454 } 455 456 if resp == nil { 457 return nil 458 } 459 460 hdr, ok := resp.Headers[name] 461 if !ok { 462 return nil 463 } 464 465 return &hdr 466 } 467 468 func TestDateFormat_Spec1(t *testing.T) { 469 b, err := opBuilder("putTesting", "../fixtures/bugs/193/spec1.json") 470 if assert.NoError(t, err) { 471 op, err := b.MakeOperation() 472 if assert.NoError(t, err) { 473 buf := bytes.NewBuffer(nil) 474 opts := opts() 475 opts.defaultsEnsured = false 476 opts.IsClient = true 477 err = opts.EnsureDefaults() 478 assert.NoError(t, err) 479 err = templates.MustGet("clientParameter").Execute(buf, op) 480 if assert.NoError(t, err) { 481 ff, err := opts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes()) 482 if assert.NoError(t, err) { 483 res := string(ff) 484 assertInCode(t, "frTestingThis.String()", res) 485 } else { 486 fmt.Println(buf.String()) 487 } 488 } 489 } 490 } 491 } 492 493 func TestDateFormat_Spec2(t *testing.T) { 494 b, err := opBuilder("putTesting", "../fixtures/bugs/193/spec2.json") 495 if assert.NoError(t, err) { 496 op, err := b.MakeOperation() 497 if assert.NoError(t, err) { 498 buf := bytes.NewBuffer(nil) 499 opts := opts() 500 opts.defaultsEnsured = false 501 opts.IsClient = true 502 err = opts.EnsureDefaults() 503 assert.NoError(t, err) 504 err = templates.MustGet("clientParameter").Execute(buf, op) 505 if assert.NoError(t, err) { 506 ff, err := opts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes()) 507 if assert.NoError(t, err) { 508 res := string(ff) 509 assertInCode(t, "valuesTestingThis = append(valuesTestingThis, v.String())", res) 510 } else { 511 fmt.Println(buf.String()) 512 } 513 } 514 } 515 } 516 } 517 518 func TestBuilder_Issue1703(t *testing.T) { 519 log.SetOutput(ioutil.Discard) 520 defer log.SetOutput(os.Stdout) 521 dr, err := os.Getwd() 522 assert.NoError(t, err) 523 524 opts := &GenOpts{ 525 Spec: filepath.FromSlash("../fixtures/codegen/existing-model.yml"), 526 IncludeModel: true, 527 IncludeValidator: true, 528 IncludeHandler: true, 529 IncludeParameters: true, 530 IncludeResponses: true, 531 IncludeMain: true, 532 APIPackage: "restapi", 533 ModelPackage: "model", 534 ServerPackage: "server", 535 ClientPackage: "client", 536 Target: dr, 537 } 538 err = opts.EnsureDefaults() 539 assert.NoError(t, err) 540 appGen, err := newAppGenerator("x-go-type-import-bug", nil, nil, opts) 541 if assert.NoError(t, err) { 542 op, err := appGen.makeCodegenApp() 543 if assert.NoError(t, err) { 544 for _, o := range op.Operations { 545 buf := bytes.NewBuffer(nil) 546 err := templates.MustGet("serverResponses").Execute(buf, o) 547 if assert.NoError(t, err) { 548 ff, err := appGen.GenOpts.LanguageOpts.FormatContent("response.go", buf.Bytes()) 549 if assert.NoError(t, err) { 550 res := string(ff) 551 assertInCode(t, "jwk \"github.com/user/package\"", res) 552 } else { 553 fmt.Println(buf.String()) 554 } 555 } 556 } 557 } 558 } 559 } 560 561 func TestBuilder_Issue287(t *testing.T) { 562 log.SetOutput(ioutil.Discard) 563 defer log.SetOutput(os.Stdout) 564 dr, _ := os.Getwd() 565 566 opts := &GenOpts{ 567 Spec: filepath.FromSlash("../fixtures/bugs/287/swagger.yml"), 568 IncludeModel: true, 569 IncludeValidator: true, 570 IncludeHandler: true, 571 IncludeParameters: true, 572 IncludeResponses: true, 573 IncludeMain: true, 574 APIPackage: "restapi", 575 ModelPackage: "model", 576 ServerPackage: "server", 577 ClientPackage: "client", 578 Target: dr, 579 } 580 err := opts.EnsureDefaults() 581 assert.NoError(t, err) 582 appGen, err := newAppGenerator("plainTexter", nil, nil, opts) 583 if assert.NoError(t, err) { 584 op, err := appGen.makeCodegenApp() 585 if assert.NoError(t, err) { 586 buf := bytes.NewBuffer(nil) 587 err := templates.MustGet("serverBuilder").Execute(buf, op) 588 if assert.NoError(t, err) { 589 ff, err := appGen.GenOpts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes()) 590 if assert.NoError(t, err) { 591 res := string(ff) 592 assertInCode(t, "case \"text/plain\":", res) 593 } else { 594 fmt.Println(buf.String()) 595 } 596 } 597 } 598 } 599 } 600 601 func TestBuilder_Issue465(t *testing.T) { 602 log.SetOutput(ioutil.Discard) 603 defer log.SetOutput(os.Stdout) 604 dr, _ := os.Getwd() 605 opts := &GenOpts{ 606 Spec: filepath.FromSlash("../fixtures/bugs/465/swagger.yml"), 607 IncludeModel: true, 608 IncludeValidator: true, 609 IncludeHandler: true, 610 IncludeParameters: true, 611 IncludeResponses: true, 612 IncludeMain: true, 613 APIPackage: "restapi", 614 ModelPackage: "model", 615 ServerPackage: "server", 616 ClientPackage: "client", 617 Target: dr, 618 IsClient: true, 619 } 620 err := opts.EnsureDefaults() 621 assert.NoError(t, err) 622 appGen, err := newAppGenerator("plainTexter", nil, nil, opts) 623 624 if assert.NoError(t, err) { 625 op, err := appGen.makeCodegenApp() 626 if assert.NoError(t, err) { 627 buf := bytes.NewBuffer(nil) 628 err := templates.MustGet("clientFacade").Execute(buf, op) 629 if assert.NoError(t, err) { 630 ff, err := appGen.GenOpts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes()) 631 if assert.NoError(t, err) { 632 res := string(ff) 633 assertInCode(t, "/v1/fancyAPI", res) 634 } else { 635 fmt.Println(buf.String()) 636 } 637 } 638 } 639 } 640 } 641 642 func TestBuilder_Issue500(t *testing.T) { 643 log.SetOutput(ioutil.Discard) 644 defer log.SetOutput(os.Stdout) 645 dr, _ := os.Getwd() 646 opts := &GenOpts{ 647 Spec: filepath.FromSlash("../fixtures/bugs/500/swagger.yml"), 648 IncludeModel: true, 649 IncludeValidator: true, 650 IncludeHandler: true, 651 IncludeParameters: true, 652 IncludeResponses: true, 653 IncludeMain: true, 654 APIPackage: "restapi", 655 ModelPackage: "model", 656 ServerPackage: "server", 657 ClientPackage: "client", 658 Target: dr, 659 } 660 err := opts.EnsureDefaults() 661 assert.NoError(t, err) 662 appGen, err := newAppGenerator("multiTags", nil, nil, opts) 663 if assert.NoError(t, err) { 664 op, err := appGen.makeCodegenApp() 665 if assert.NoError(t, err) { 666 buf := bytes.NewBuffer(nil) 667 err := templates.MustGet("serverBuilder").Execute(buf, op) 668 if assert.NoError(t, err) { 669 ff, err := appGen.GenOpts.LanguageOpts.FormatContent("put_testing.go", buf.Bytes()) 670 if assert.NoError(t, err) { 671 res := string(ff) 672 assertNotInCode(t, `o.handlers["GET"]["/payment/{invoice_id}/payments/{payment_id}"] = NewGetPaymentByID(o.context, o.GetPaymentByIDHandler)`, res) 673 assertInCode(t, `o.handlers["GET"]["/payment/{invoice_id}/payments/{payment_id}"] = invoices.NewGetPaymentByID(o.context, o.InvoicesGetPaymentByIDHandler)`, res) 674 } else { 675 fmt.Println(buf.String()) 676 } 677 } 678 } 679 } 680 } 681 682 func TestGenClient_IllegalBOM(t *testing.T) { 683 b, err := methodPathOpBuilder("get", "/v3/attachments/{attachmentId}", "../fixtures/bugs/727/swagger.json") 684 if assert.NoError(t, err) { 685 op, err := b.MakeOperation() 686 if assert.NoError(t, err) { 687 buf := bytes.NewBuffer(nil) 688 opts := opts() 689 opts.defaultsEnsured = false 690 opts.IsClient = true 691 err = opts.EnsureDefaults() 692 assert.NoError(t, err) 693 err = templates.MustGet("clientResponse").Execute(buf, op) 694 assert.NoError(t, err) 695 } 696 } 697 } 698 699 func TestGenClient_CustomFormatPath(t *testing.T) { 700 b, err := methodPathOpBuilder("get", "/mosaic/experimental/series/{SeriesId}/mosaics", "../fixtures/bugs/789/swagger.yml") 701 if assert.NoError(t, err) { 702 op, err := b.MakeOperation() 703 if assert.NoError(t, err) { 704 buf := bytes.NewBuffer(nil) 705 opts := opts() 706 opts.defaultsEnsured = false 707 opts.IsClient = true 708 err = opts.EnsureDefaults() 709 assert.NoError(t, err) 710 err = templates.MustGet("clientParameter").Execute(buf, op) 711 if assert.NoError(t, err) { 712 assertInCode(t, `if err := r.SetPathParam("SeriesId", o.SeriesID.String()); err != nil`, buf.String()) 713 } 714 } 715 } 716 } 717 718 func TestGenClient_Issue733(t *testing.T) { 719 b, err := opBuilder("get_characters_character_id_mail_mail_id", "../fixtures/bugs/733/swagger.json") 720 if assert.NoError(t, err) { 721 op, err := b.MakeOperation() 722 if assert.NoError(t, err) { 723 buf := bytes.NewBuffer(nil) 724 opts := opts() 725 opts.defaultsEnsured = false 726 opts.IsClient = true 727 err = opts.EnsureDefaults() 728 assert.NoError(t, err) 729 err = templates.MustGet("clientResponse").Execute(buf, op) 730 if assert.NoError(t, err) { 731 assertInCode(t, "Labels []*int64 `json:\"labels\"`", buf.String()) 732 } 733 } 734 } 735 } 736 737 func TestGenServerIssue890_ValidationTrueFlatteningTrue(t *testing.T) { 738 log.SetOutput(ioutil.Discard) 739 defer log.SetOutput(os.Stdout) 740 dr, _ := os.Getwd() 741 opts := &GenOpts{ 742 Spec: filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"), 743 IncludeModel: true, 744 IncludeValidator: true, 745 IncludeHandler: true, 746 IncludeParameters: true, 747 IncludeResponses: true, 748 IncludeMain: true, 749 ValidateSpec: true, 750 APIPackage: "restapi", 751 ModelPackage: "model", 752 ServerPackage: "server", 753 ClientPackage: "client", 754 Target: dr, 755 IsClient: true, 756 } 757 758 //Testing Server Generation 759 err := opts.EnsureDefaults() 760 // Full flattening 761 opts.FlattenOpts.Expand = false 762 opts.FlattenOpts.Minimal = false 763 assert.NoError(t, err) 764 appGen, err := newAppGenerator("JsonRefOperation", nil, nil, opts) 765 if assert.NoError(t, err) { 766 op, err := appGen.makeCodegenApp() 767 if assert.NoError(t, err) { 768 buf := bytes.NewBuffer(nil) 769 err := templates.MustGet("serverOperation").Execute(buf, op.Operations[0]) 770 if assert.NoError(t, err) { 771 filecontent, err := appGen.GenOpts.LanguageOpts.FormatContent("operation.go", buf.Bytes()) 772 if assert.NoError(t, err) { 773 res := string(filecontent) 774 assertInCode(t, "GetHealthCheck", res) 775 } else { 776 fmt.Println(buf.String()) 777 } 778 } 779 } 780 } 781 } 782 783 func TestGenClientIssue890_ValidationTrueFlatteningTrue(t *testing.T) { 784 log.SetOutput(ioutil.Discard) 785 defer func() { 786 log.SetOutput(os.Stdout) 787 dr, _ := os.Getwd() 788 _ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi")) 789 }() 790 opts := testGenOpts() 791 opts.Spec = "../fixtures/bugs/890/swagger.yaml" 792 opts.ValidateSpec = true 793 opts.FlattenOpts.Minimal = false 794 // Testing this is enough as there is only one operation which is specified as $ref. 795 // If this doesn't get resolved then there will be an error definitely. 796 assert.NoError(t, GenerateClient("foo", nil, nil, &opts)) 797 } 798 799 func TestGenServerIssue890_ValidationFalseFlattenTrue(t *testing.T) { 800 log.SetOutput(ioutil.Discard) 801 defer log.SetOutput(os.Stdout) 802 dr, _ := os.Getwd() 803 opts := &GenOpts{ 804 Spec: filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"), 805 IncludeModel: true, 806 IncludeValidator: true, 807 IncludeHandler: true, 808 IncludeParameters: true, 809 IncludeResponses: true, 810 IncludeMain: true, 811 APIPackage: "restapi", 812 ModelPackage: "model", 813 ServerPackage: "server", 814 ClientPackage: "client", 815 Target: dr, 816 IsClient: true, 817 } 818 819 //Testing Server Generation 820 err := opts.EnsureDefaults() 821 // full flattening 822 opts.FlattenOpts.Minimal = false 823 assert.NoError(t, err) 824 appGen, err := newAppGenerator("JsonRefOperation", nil, nil, opts) 825 if assert.NoError(t, err) { 826 op, err := appGen.makeCodegenApp() 827 if assert.NoError(t, err) { 828 buf := bytes.NewBuffer(nil) 829 err := templates.MustGet("serverOperation").Execute(buf, op.Operations[0]) 830 if assert.NoError(t, err) { 831 filecontent, err := appGen.GenOpts.LanguageOpts.FormatContent("operation.go", buf.Bytes()) 832 if assert.NoError(t, err) { 833 res := string(filecontent) 834 assertInCode(t, "GetHealthCheck", res) 835 } else { 836 fmt.Println(buf.String()) 837 } 838 } 839 } 840 } 841 } 842 843 func TestGenClientIssue890_ValidationFalseFlatteningTrue(t *testing.T) { 844 log.SetOutput(ioutil.Discard) 845 defer func() { 846 log.SetOutput(os.Stdout) 847 dr, _ := os.Getwd() 848 _ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi")) 849 }() 850 opts := testGenOpts() 851 opts.Spec = "../fixtures/bugs/890/swagger.yaml" 852 opts.ValidateSpec = false 853 // full flattening 854 opts.FlattenOpts.Minimal = false 855 // Testing this is enough as there is only one operation which is specified as $ref. 856 // If this doesn't get resolved then there will be an error definitely. 857 assert.NoError(t, GenerateClient("foo", nil, nil, &opts)) 858 } 859 860 func TestGenServerIssue890_ValidationFalseFlattenFalse(t *testing.T) { 861 log.SetOutput(ioutil.Discard) 862 defer log.SetOutput(os.Stdout) 863 dr, _ := os.Getwd() 864 opts := &GenOpts{ 865 Spec: filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"), 866 IncludeModel: true, 867 IncludeValidator: true, 868 IncludeHandler: true, 869 IncludeParameters: true, 870 IncludeResponses: true, 871 IncludeMain: true, 872 ValidateSpec: false, 873 APIPackage: "restapi", 874 ModelPackage: "model", 875 ServerPackage: "server", 876 ClientPackage: "client", 877 Target: dr, 878 IsClient: true, 879 } 880 881 //Testing Server Generation 882 err := opts.EnsureDefaults() 883 // minimal flattening 884 opts.FlattenOpts.Minimal = true 885 assert.NoError(t, err) 886 _, err = newAppGenerator("JsonRefOperation", nil, nil, opts) 887 // if flatten is not set, expand takes over so this would resume normally 888 assert.NoError(t, err) 889 } 890 891 func TestGenClientIssue890_ValidationFalseFlattenFalse(t *testing.T) { 892 log.SetOutput(ioutil.Discard) 893 defer func() { 894 dr, _ := os.Getwd() 895 _ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi")) 896 log.SetOutput(os.Stdout) 897 }() 898 opts := testGenOpts() 899 opts.Spec = "../fixtures/bugs/890/swagger.yaml" 900 opts.ValidateSpec = false 901 // minimal flattening 902 opts.FlattenOpts.Minimal = true 903 // Testing this is enough as there is only one operation which is specified as $ref. 904 // If this doesn't get resolved then there will be an error definitely. 905 // New: Now if flatten is false, expand takes over so server generation should resume normally 906 assert.NoError(t, GenerateClient("foo", nil, nil, &opts)) 907 } 908 909 func TestGenServerIssue890_ValidationTrueFlattenFalse(t *testing.T) { 910 log.SetOutput(ioutil.Discard) 911 defer log.SetOutput(os.Stdout) 912 dr, _ := os.Getwd() 913 opts := &GenOpts{ 914 Spec: filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"), 915 IncludeModel: true, 916 IncludeValidator: true, 917 IncludeHandler: true, 918 IncludeParameters: true, 919 IncludeResponses: true, 920 IncludeMain: true, 921 ValidateSpec: true, 922 APIPackage: "restapi", 923 ModelPackage: "model", 924 ServerPackage: "server", 925 ClientPackage: "client", 926 Target: dr, 927 IsClient: true, 928 } 929 930 //Testing Server Generation 931 err := opts.EnsureDefaults() 932 // minimal flattening 933 opts.FlattenOpts.Minimal = true 934 assert.NoError(t, err) 935 _, err = newAppGenerator("JsonRefOperation", nil, nil, opts) 936 // now if flatten is false, expand takes over so server generation should resume normally 937 assert.NoError(t, err) 938 } 939 940 func TestGenServerWithTemplate(t *testing.T) { 941 log.SetOutput(ioutil.Discard) 942 defer log.SetOutput(os.Stdout) 943 dr, _ := os.Getwd() 944 945 tests := []struct { 946 name string 947 opts *GenOpts 948 wantError bool 949 }{ 950 { 951 name: "None_existing_contributor_tempalte", 952 opts: &GenOpts{ 953 Spec: filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"), 954 IncludeModel: true, 955 IncludeValidator: true, 956 IncludeHandler: true, 957 IncludeParameters: true, 958 IncludeResponses: true, 959 IncludeMain: true, 960 ValidateSpec: true, 961 APIPackage: "restapi", 962 ModelPackage: "model", 963 ServerPackage: "server", 964 ClientPackage: "client", 965 Target: dr, 966 IsClient: true, 967 Template: "InvalidTemplate", 968 }, 969 wantError: true, 970 }, 971 { 972 name: "Existing_contributor", 973 opts: &GenOpts{ 974 Spec: filepath.FromSlash("../fixtures/bugs/890/swagger.yaml"), 975 IncludeModel: true, 976 IncludeValidator: true, 977 IncludeHandler: true, 978 IncludeParameters: true, 979 IncludeResponses: true, 980 IncludeMain: true, 981 ValidateSpec: true, 982 APIPackage: "restapi", 983 ModelPackage: "model", 984 ServerPackage: "server", 985 ClientPackage: "client", 986 Target: dr, 987 IsClient: true, 988 Template: "stratoscale", 989 }, 990 wantError: false, 991 }, 992 } 993 994 for _, tt := range tests { 995 t.Run(tt.name, func(t *testing.T) { 996 //Testing Server Generation 997 err := tt.opts.EnsureDefaults() 998 // minimal flattening 999 tt.opts.FlattenOpts.Minimal = true 1000 assert.NoError(t, err) 1001 _, err = newAppGenerator("JsonRefOperation", nil, nil, tt.opts) 1002 if tt.wantError { 1003 assert.Error(t, err) 1004 } else { 1005 assert.NoError(t, err) 1006 } 1007 }) 1008 } 1009 } 1010 1011 func TestGenClientIssue890_ValidationTrueFlattenFalse(t *testing.T) { 1012 log.SetOutput(ioutil.Discard) 1013 defer func() { 1014 log.SetOutput(os.Stdout) 1015 dr, _ := os.Getwd() 1016 _ = os.RemoveAll(filepath.Join(filepath.FromSlash(dr), "restapi")) 1017 }() 1018 opts := testGenOpts() 1019 opts.Spec = filepath.FromSlash("../fixtures/bugs/890/swagger.yaml") 1020 opts.ValidateSpec = true 1021 // Testing this is enough as there is only one operation which is specified as $ref. 1022 // If this doesn't get resolved then there will be an error definitely. 1023 // same here: now if flatten doesn't resume, expand takes over 1024 assert.NoError(t, GenerateClient("foo", nil, nil, &opts)) 1025 } 1026 1027 // This tests that securityDefinitions generate stable code 1028 func TestBuilder_Issue1214(t *testing.T) { 1029 const any = `(.|\n)+` 1030 log.SetOutput(ioutil.Discard) 1031 defer log.SetOutput(os.Stdout) 1032 dr, _ := os.Getwd() 1033 opts := &GenOpts{ 1034 Spec: filepath.FromSlash("../fixtures/bugs/1214/fixture-1214.yaml"), 1035 IncludeModel: true, 1036 IncludeValidator: true, 1037 IncludeHandler: true, 1038 IncludeParameters: true, 1039 IncludeResponses: true, 1040 IncludeMain: true, 1041 APIPackage: "restapi", 1042 ModelPackage: "model", 1043 ServerPackage: "server", 1044 ClientPackage: "client", 1045 Target: dr, 1046 IsClient: false, 1047 } 1048 err := opts.EnsureDefaults() 1049 assert.NoError(t, err) 1050 appGen, err := newAppGenerator("fixture-1214", nil, nil, opts) 1051 if assert.NoError(t, err) { 1052 op, err := appGen.makeCodegenApp() 1053 if assert.NoError(t, err) { 1054 for i := 0; i < 5; i++ { 1055 buf := bytes.NewBuffer(nil) 1056 ert := templates.MustGet("serverConfigureapi").Execute(buf, op) 1057 if assert.NoError(t, ert) { 1058 ff, erf := appGen.GenOpts.LanguageOpts.FormatContent("fixture_1214_configure_api.go", buf.Bytes()) 1059 if assert.NoError(t, erf) { 1060 res := string(ff) 1061 assertRegexpInCode(t, any+ 1062 `api\.AAuth = func\(user string, pass string\)`+any+ 1063 `api\.BAuth = func\(token string\)`+any+ 1064 `api\.CAuth = func\(token string\)`+any+ 1065 `api\.DAuth = func\(token string\)`+any+ 1066 `api\.EAuth = func\(token string, scopes \[\]string\)`+any, res) 1067 } else { 1068 fmt.Println(buf.String()) 1069 break 1070 } 1071 } else { 1072 break 1073 } 1074 buf = bytes.NewBuffer(nil) 1075 err = templates.MustGet("serverBuilder").Execute(buf, op) 1076 if assert.NoError(t, err) { 1077 ff, err := appGen.GenOpts.LanguageOpts.FormatContent("fixture_1214_server.go", buf.Bytes()) 1078 if assert.NoError(t, err) { 1079 res := string(ff) 1080 assertRegexpInCode(t, any+ 1081 `AAuth: func\(user string, pass string\) \(interface{}, error\) {`+any+ 1082 `BAuth: func\(token string\) \(interface{}, error\) {`+any+ 1083 `CAuth: func\(token string\) \(interface{}, error\) {`+any+ 1084 `DAuth: func\(token string\) \(interface{}, error\) {`+any+ 1085 `EAuth: func\(token string, scopes \[\]string\) \(interface{}, error\) {`+any+ 1086 1087 `AAuth func\(string, string\) \(interface{}, error\)`+any+ 1088 `BAuth func\(string\) \(interface{}, error\)`+any+ 1089 `CAuth func\(string\) \(interface{}, error\)`+any+ 1090 `DAuth func\(string\) \(interface{}, error\)`+any+ 1091 `EAuth func\(string, \[\]string\) \(interface{}, error\)`+any+ 1092 1093 `if o\.AAuth == nil {`+any+ 1094 `unregistered = append\(unregistered, "AAuth"\)`+any+ 1095 `if o\.BAuth == nil {`+any+ 1096 `unregistered = append\(unregistered, "K1Auth"\)`+any+ 1097 `if o\.CAuth == nil {`+any+ 1098 `unregistered = append\(unregistered, "K2Auth"\)`+any+ 1099 `if o\.DAuth == nil {`+any+ 1100 `unregistered = append\(unregistered, "K3Auth"\)`+any+ 1101 `if o\.EAuth == nil {`+any+ 1102 `unregistered = append\(unregistered, "EAuth"\)`+any+ 1103 1104 `case "A":`+any+ 1105 `case "B":`+any+ 1106 `case "C":`+any+ 1107 `case "D":`+any+ 1108 `case "E":`+any, res) 1109 } else { 1110 fmt.Println(buf.String()) 1111 break 1112 } 1113 } else { 1114 break 1115 } 1116 } 1117 } 1118 } 1119 } 1120 1121 func TestGenSecurityRequirements(t *testing.T) { 1122 for i := 0; i < 5; i++ { 1123 operation := "asecOp" 1124 b, err := opBuilder(operation, "../fixtures/bugs/1214/fixture-1214.yaml") 1125 if !assert.NoError(t, err) { 1126 t.FailNow() 1127 return 1128 } 1129 b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation) 1130 genRequirements := b.makeSecurityRequirements("o") 1131 assert.Len(t, genRequirements, 2) 1132 assert.Equal(t, []GenSecurityRequirements{ 1133 { 1134 GenSecurityRequirement{ 1135 Name: "A", 1136 Scopes: []string{}, 1137 }, 1138 GenSecurityRequirement{ 1139 Name: "B", 1140 Scopes: []string{}, 1141 }, 1142 GenSecurityRequirement{ 1143 Name: "E", 1144 Scopes: []string{"s0", "s1", "s2", "s3", "s4"}, 1145 }, 1146 }, 1147 { 1148 GenSecurityRequirement{ 1149 Name: "C", 1150 Scopes: []string{}, 1151 }, 1152 GenSecurityRequirement{ 1153 Name: "D", 1154 Scopes: []string{}, 1155 }, 1156 GenSecurityRequirement{ 1157 Name: "E", 1158 Scopes: []string{"s5", "s6", "s7", "s8", "s9"}, 1159 }, 1160 }, 1161 }, genRequirements) 1162 1163 operation = "bsecOp" 1164 b, err = opBuilder(operation, "../fixtures/bugs/1214/fixture-1214.yaml") 1165 if !assert.NoError(t, err) { 1166 t.FailNow() 1167 return 1168 } 1169 b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation) 1170 genRequirements = b.makeSecurityRequirements("o") 1171 assert.Len(t, genRequirements, 2) 1172 assert.Equal(t, []GenSecurityRequirements{ 1173 { 1174 GenSecurityRequirement{ 1175 Name: "A", 1176 Scopes: []string{}, 1177 }, 1178 GenSecurityRequirement{ 1179 Name: "E", 1180 Scopes: []string{"s0", "s1", "s2", "s3", "s4"}, 1181 }, 1182 }, 1183 { 1184 GenSecurityRequirement{ 1185 Name: "D", 1186 Scopes: []string{}, 1187 }, 1188 GenSecurityRequirement{ 1189 Name: "E", 1190 Scopes: []string{"s5", "s6", "s7", "s8", "s9"}, 1191 }, 1192 }, 1193 }, genRequirements) 1194 } 1195 1196 operation := "csecOp" 1197 b, err := opBuilder(operation, "../fixtures/bugs/1214/fixture-1214.yaml") 1198 if !assert.NoError(t, err) { 1199 t.FailNow() 1200 return 1201 } 1202 b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation) 1203 genRequirements := b.makeSecurityRequirements("o") 1204 assert.NotNil(t, genRequirements) 1205 assert.Len(t, genRequirements, 0) 1206 1207 operation = "nosecOp" 1208 b, err = opBuilder(operation, "../fixtures/bugs/1214/fixture-1214-2.yaml") 1209 if !assert.NoError(t, err) { 1210 t.FailNow() 1211 return 1212 } 1213 b.Security = b.Analyzed.SecurityRequirementsFor(&b.Operation) 1214 genRequirements = b.makeSecurityRequirements("o") 1215 assert.Nil(t, genRequirements) 1216 } 1217 1218 func TestGenerateServerOperation(t *testing.T) { 1219 log.SetOutput(ioutil.Discard) 1220 defer log.SetOutput(os.Stdout) 1221 fname := "../fixtures/codegen/todolist.simple.yml" 1222 1223 tgt, _ := ioutil.TempDir(filepath.Dir(fname), "generated") 1224 defer func() { 1225 _ = os.RemoveAll(tgt) 1226 }() 1227 o := &GenOpts{ 1228 IncludeValidator: true, 1229 ValidateSpec: false, 1230 IncludeModel: true, 1231 IncludeHandler: true, 1232 IncludeParameters: true, 1233 IncludeResponses: true, 1234 ModelPackage: "models", 1235 Spec: fname, 1236 Target: tgt, 1237 } 1238 if err := o.EnsureDefaults(); err != nil { 1239 panic(err) 1240 } 1241 1242 err := GenerateServerOperation([]string{"createTask"}, nil) 1243 assert.Error(t, err) 1244 1245 d := o.TemplateDir 1246 o.TemplateDir = "./nowhere" 1247 err = GenerateServerOperation([]string{"notFound"}, o) 1248 assert.Error(t, err) 1249 o.TemplateDir = d 1250 1251 d = o.Spec 1252 o.Spec = "nowhere.yaml" 1253 err = GenerateServerOperation([]string{"notFound"}, o) 1254 assert.Error(t, err) 1255 o.Spec = d 1256 1257 err = GenerateServerOperation([]string{"notFound"}, o) 1258 assert.Error(t, err) 1259 1260 err = GenerateServerOperation([]string{"createTask"}, o) 1261 if !assert.NoError(t, err) { 1262 t.FailNow() 1263 return 1264 } 1265 // check expected files are generated and that's it 1266 _, err = os.Stat(filepath.Join(tgt, "tasks", "create_task.go")) 1267 assert.NoError(t, err) 1268 _, err = os.Stat(filepath.Join(tgt, "tasks", "create_task_parameters.go")) 1269 assert.NoError(t, err) 1270 _, err = os.Stat(filepath.Join(tgt, "tasks", "create_task_responses.go")) 1271 assert.NoError(t, err) 1272 1273 origStdout := os.Stdout 1274 defer func() { 1275 os.Stdout = origStdout 1276 }() 1277 os.Stdout, _ = os.Create(filepath.Join(tgt, "stdout")) 1278 o.DumpData = true 1279 // just checks this does not fail 1280 err = GenerateServerOperation([]string{"createTask"}, o) 1281 assert.NoError(t, err) 1282 _, err = os.Stat(filepath.Join(tgt, "stdout")) 1283 assert.NoError(t, err) 1284 } 1285 1286 // This tests that mimetypes generate stable code 1287 func TestBuilder_Issue1646(t *testing.T) { 1288 log.SetOutput(ioutil.Discard) 1289 defer log.SetOutput(os.Stdout) 1290 dr, _ := os.Getwd() 1291 opts := &GenOpts{ 1292 Spec: filepath.FromSlash("../fixtures/bugs/1646/fixture-1646.yaml"), 1293 IncludeModel: true, 1294 IncludeValidator: true, 1295 IncludeHandler: true, 1296 IncludeParameters: true, 1297 IncludeResponses: true, 1298 IncludeMain: true, 1299 APIPackage: "restapi", 1300 ModelPackage: "model", 1301 ServerPackage: "server", 1302 ClientPackage: "client", 1303 Target: dr, 1304 IsClient: false, 1305 } 1306 err := opts.EnsureDefaults() 1307 assert.NoError(t, err) 1308 appGen, err := newAppGenerator("fixture-1646", nil, nil, opts) 1309 1310 if assert.NoError(t, err) { 1311 preCons, preConj := appGen.makeConsumes() 1312 preProds, preProdj := appGen.makeProduces() 1313 assert.True(t, preConj) 1314 assert.True(t, preProdj) 1315 for i := 0; i < 5; i++ { 1316 cons, conj := appGen.makeConsumes() 1317 prods, prodj := appGen.makeProduces() 1318 assert.True(t, conj) 1319 assert.True(t, prodj) 1320 assert.Equal(t, preConj, conj) 1321 assert.Equal(t, preProdj, prodj) 1322 assert.Equal(t, preCons, cons) 1323 assert.Equal(t, preProds, prods) 1324 } 1325 } 1326 } 1327 1328 func TestGenServer_StrictAdditionalProperties(t *testing.T) { 1329 log.SetOutput(ioutil.Discard) 1330 defer log.SetOutput(os.Stdout) 1331 dr, _ := os.Getwd() 1332 opts := &GenOpts{ 1333 Spec: filepath.FromSlash("../fixtures/codegen/strict-additional-properties.yml"), 1334 IncludeModel: true, 1335 IncludeValidator: true, 1336 IncludeHandler: true, 1337 IncludeParameters: true, 1338 IncludeResponses: true, 1339 IncludeMain: true, 1340 APIPackage: "restapi", 1341 ModelPackage: "model", 1342 ServerPackage: "server", 1343 ClientPackage: "client", 1344 Target: dr, 1345 IsClient: false, 1346 } 1347 if err := opts.EnsureDefaults(); err != nil { 1348 panic(err) 1349 } 1350 1351 opts.StrictAdditionalProperties = true 1352 1353 appGen, err := newAppGenerator("StrictAdditionalProperties", nil, nil, opts) 1354 if assert.NoError(t, err) { 1355 op, err := appGen.makeCodegenApp() 1356 if assert.NoError(t, err) { 1357 buf := bytes.NewBuffer(nil) 1358 err := templates.MustGet("serverOperation").Execute(buf, op.Operations[0]) 1359 if assert.NoError(t, err) { 1360 ff, err := appGen.GenOpts.LanguageOpts.FormatContent("strictAdditionalProperties.go", buf.Bytes()) 1361 if assert.NoError(t, err) { 1362 res := string(ff) 1363 for _, tt := range []struct { 1364 name string 1365 assertion func(testing.TB, string, string) bool 1366 }{ 1367 {"PostTestBody", assertInCode}, 1368 {"PostTestParamsBodyExplicit", assertInCode}, 1369 {"PostTestParamsBodyImplicit", assertInCode}, 1370 {"PostTestParamsBodyDisabled", assertNotInCode}, 1371 } { 1372 fn := funcBody(res, "*"+tt.name+") UnmarshalJSON(data []byte) error") 1373 if assert.NotEmpty(t, fn, "Method UnmarshalJSON should be defined for type *"+tt.name) { 1374 tt.assertion(t, "dec.DisallowUnknownFields()", fn) 1375 } 1376 } 1377 } else { 1378 fmt.Println(buf.String()) 1379 } 1380 } 1381 } 1382 } 1383 }