github.com/brycereitano/goa@v0.0.0-20170315073847-8ffa6c85e265/goagen/gen_swagger/swagger_test.go (about) 1 package genswagger_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 7 "github.com/go-openapi/loads" 8 _ "github.com/goadesign/goa-cellar/design" 9 . "github.com/goadesign/goa/design" 10 . "github.com/goadesign/goa/design/apidsl" 11 "github.com/goadesign/goa/dslengine" 12 "github.com/goadesign/goa/goagen/gen_schema" 13 "github.com/goadesign/goa/goagen/gen_swagger" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 ) 17 18 // validateSwagger validates that the given swagger object represents a valid Swagger spec. 19 func validateSwagger(swagger *genswagger.Swagger) { 20 b, err := json.Marshal(swagger) 21 Ω(err).ShouldNot(HaveOccurred()) 22 doc, err := loads.Analyzed(json.RawMessage(b), "") 23 Ω(err).ShouldNot(HaveOccurred()) 24 Ω(doc).ShouldNot(BeNil()) 25 } 26 27 // validateSwaggerWithFragments validates that the given swagger object represents a valid Swagger spec 28 // and contains fragments 29 func validateSwaggerWithFragments(swagger *genswagger.Swagger, fragments [][]byte) { 30 b, err := json.Marshal(swagger) 31 Ω(err).ShouldNot(HaveOccurred()) 32 doc, err := loads.Analyzed(json.RawMessage(b), "") 33 Ω(err).ShouldNot(HaveOccurred()) 34 Ω(doc).ShouldNot(BeNil()) 35 for _, sub := range fragments { 36 Ω(bytes.Contains(b, sub)).Should(BeTrue()) 37 } 38 } 39 40 var _ = Describe("New", func() { 41 var swagger *genswagger.Swagger 42 var newErr error 43 44 BeforeEach(func() { 45 swagger = nil 46 newErr = nil 47 dslengine.Reset() 48 genschema.Definitions = make(map[string]*genschema.JSONSchema) 49 }) 50 51 JustBeforeEach(func() { 52 err := dslengine.Run() 53 Ω(err).ShouldNot(HaveOccurred()) 54 swagger, newErr = genswagger.New(Design) 55 }) 56 57 Context("with a valid API definition", func() { 58 const ( 59 title = "title" 60 description = "description" 61 terms = "terms" 62 contactEmail = "contactEmail@goa.design" 63 contactName = "contactName" 64 contactURL = "http://contactURL.com" 65 license = "license" 66 licenseURL = "http://licenseURL.com" 67 host = "host" 68 scheme = "https" 69 basePath = "/base" 70 tag = "tag" 71 docDesc = "doc description" 72 docURL = "http://docURL.com" 73 ) 74 75 BeforeEach(func() { 76 API("test", func() { 77 Title(title) 78 Metadata("swagger:tag:" + tag) 79 Metadata("swagger:tag:"+tag+":desc", "Tag desc.") 80 Metadata("swagger:tag:"+tag+":url", "http://example.com/tag") 81 Metadata("swagger:tag:"+tag+":url:desc", "Huge docs") 82 Description(description) 83 TermsOfService(terms) 84 Contact(func() { 85 Email(contactEmail) 86 Name(contactName) 87 URL(contactURL) 88 }) 89 License(func() { 90 Name(license) 91 URL(licenseURL) 92 }) 93 Docs(func() { 94 Description(docDesc) 95 URL(docURL) 96 }) 97 Host(host) 98 Scheme(scheme) 99 BasePath(basePath) 100 }) 101 }) 102 103 It("sets all the basic fields", func() { 104 Ω(newErr).ShouldNot(HaveOccurred()) 105 Ω(swagger).Should(Equal(&genswagger.Swagger{ 106 Swagger: "2.0", 107 Info: &genswagger.Info{ 108 Title: title, 109 Description: description, 110 TermsOfService: terms, 111 Contact: &ContactDefinition{ 112 Name: contactName, 113 Email: contactEmail, 114 URL: contactURL, 115 }, 116 License: &LicenseDefinition{ 117 Name: license, 118 URL: licenseURL, 119 }, 120 Version: "", 121 }, 122 Host: host, 123 BasePath: basePath, 124 Schemes: []string{"https"}, 125 Paths: make(map[string]interface{}), 126 Consumes: []string{"application/json", "application/xml", "application/gob", "application/x-gob"}, 127 Produces: []string{"application/json", "application/xml", "application/gob", "application/x-gob"}, 128 Tags: []*genswagger.Tag{{Name: tag, Description: "Tag desc.", ExternalDocs: &genswagger.ExternalDocs{ 129 URL: "http://example.com/tag", Description: "Huge docs", 130 }}}, 131 ExternalDocs: &genswagger.ExternalDocs{ 132 Description: docDesc, 133 URL: docURL, 134 }, 135 })) 136 }) 137 138 It("serializes into valid swagger JSON", func() { validateSwagger(swagger) }) 139 140 Context("with base params", func() { 141 const ( 142 basePath = "/s/:strParam/i/:intParam/n/:numParam/b/:boolParam" 143 strParam = "strParam" 144 intParam = "intParam" 145 numParam = "numParam" 146 boolParam = "boolParam" 147 queryParam = "queryParam" 148 description = "description" 149 intMin = 1.0 150 floatMax = 2.4 151 enum1 = "enum1" 152 enum2 = "enum2" 153 ) 154 155 BeforeEach(func() { 156 base := Design.DSLFunc 157 Design.DSLFunc = func() { 158 base() 159 BasePath(basePath) 160 Params(func() { 161 Param(strParam, String, func() { 162 Description(description) 163 Format("email") 164 }) 165 Param(intParam, Integer, func() { 166 Minimum(intMin) 167 }) 168 Param(numParam, Number, func() { 169 Maximum(floatMax) 170 }) 171 Param(boolParam, Boolean) 172 Param(queryParam, func() { 173 Enum(enum1, enum2) 174 }) 175 }) 176 } 177 }) 178 179 It("sets the BasePath and Parameters fields", func() { 180 Ω(newErr).ShouldNot(HaveOccurred()) 181 Ω(swagger.BasePath).Should(Equal(basePath)) 182 Ω(swagger.Parameters).Should(HaveLen(5)) 183 Ω(swagger.Parameters[strParam]).ShouldNot(BeNil()) 184 Ω(swagger.Parameters[strParam].Name).Should(Equal(strParam)) 185 Ω(swagger.Parameters[strParam].In).Should(Equal("path")) 186 Ω(swagger.Parameters[strParam].Description).Should(Equal("description")) 187 Ω(swagger.Parameters[strParam].Required).Should(BeTrue()) 188 Ω(swagger.Parameters[strParam].Type).Should(Equal("string")) 189 Ω(swagger.Parameters[strParam].Format).Should(Equal("email")) 190 Ω(swagger.Parameters[intParam]).ShouldNot(BeNil()) 191 Ω(swagger.Parameters[intParam].Name).Should(Equal(intParam)) 192 Ω(swagger.Parameters[intParam].In).Should(Equal("path")) 193 Ω(swagger.Parameters[intParam].Required).Should(BeTrue()) 194 Ω(swagger.Parameters[intParam].Type).Should(Equal("integer")) 195 Ω(*swagger.Parameters[intParam].Minimum).Should(Equal(intMin)) 196 Ω(swagger.Parameters[numParam]).ShouldNot(BeNil()) 197 Ω(swagger.Parameters[numParam].Name).Should(Equal(numParam)) 198 Ω(swagger.Parameters[numParam].In).Should(Equal("path")) 199 Ω(swagger.Parameters[numParam].Required).Should(BeTrue()) 200 Ω(swagger.Parameters[numParam].Type).Should(Equal("number")) 201 Ω(*swagger.Parameters[numParam].Maximum).Should(Equal(floatMax)) 202 Ω(swagger.Parameters[boolParam]).ShouldNot(BeNil()) 203 Ω(swagger.Parameters[boolParam].Name).Should(Equal(boolParam)) 204 Ω(swagger.Parameters[boolParam].In).Should(Equal("path")) 205 Ω(swagger.Parameters[boolParam].Required).Should(BeTrue()) 206 Ω(swagger.Parameters[boolParam].Type).Should(Equal("boolean")) 207 Ω(swagger.Parameters[queryParam]).ShouldNot(BeNil()) 208 Ω(swagger.Parameters[queryParam].Name).Should(Equal(queryParam)) 209 Ω(swagger.Parameters[queryParam].In).Should(Equal("query")) 210 Ω(swagger.Parameters[queryParam].Type).Should(Equal("string")) 211 Ω(swagger.Parameters[queryParam].Enum).Should(Equal([]interface{}{enum1, enum2})) 212 }) 213 214 It("serializes into valid swagger JSON", func() { validateSwagger(swagger) }) 215 }) 216 217 Context("with required payload", func() { 218 BeforeEach(func() { 219 p := Type("RequiredPayload", func() { 220 Member("m1", String) 221 }) 222 Resource("res", func() { 223 Action("act", func() { 224 Routing( 225 PUT("/"), 226 ) 227 Payload(p) 228 }) 229 }) 230 }) 231 232 It("serializes into valid swagger JSON", func() { 233 validateSwaggerWithFragments(swagger, [][]byte{ 234 []byte(`"required":true`), 235 }) 236 }) 237 }) 238 239 Context("with a payload of type Any", func() { 240 BeforeEach(func() { 241 Resource("res", func() { 242 Action("act", func() { 243 Routing( 244 PUT("/"), 245 ) 246 Payload(Any, func() { 247 Example("example") 248 }) 249 }) 250 }) 251 }) 252 253 It("serializes into valid swagger JSON", func() { 254 validateSwaggerWithFragments(swagger, [][]byte{ 255 []byte(`"ActResPayload":{"title":"ActResPayload","example":"example"}`), 256 }) 257 }) 258 259 }) 260 261 Context("with optional payload", func() { 262 BeforeEach(func() { 263 p := Type("OptionalPayload", func() { 264 Member("m1", String) 265 }) 266 Resource("res", func() { 267 Action("act", func() { 268 Routing( 269 PUT("/"), 270 ) 271 OptionalPayload(p) 272 }) 273 }) 274 }) 275 276 It("serializes into valid swagger JSON", func() { 277 validateSwaggerWithFragments(swagger, [][]byte{ 278 []byte(`"required":false`), 279 }) 280 }) 281 282 }) 283 284 Context("with zero value validations", func() { 285 const ( 286 intParam = "intParam" 287 numParam = "numParam" 288 strParam = "strParam" 289 intMin = 0.0 290 floatMax = 0.0 291 ) 292 293 BeforeEach(func() { 294 PayloadWithZeroValueValidations := Type("PayloadWithZeroValueValidations", func() { 295 Attribute(strParam, String, func() { 296 MinLength(0) 297 MaxLength(0) 298 }) 299 }) 300 Resource("res", func() { 301 Action("act", func() { 302 Routing( 303 PUT("/"), 304 ) 305 Params(func() { 306 Param(intParam, Integer, func() { 307 Minimum(intMin) 308 }) 309 Param(numParam, Number, func() { 310 Maximum(floatMax) 311 }) 312 }) 313 Payload(PayloadWithZeroValueValidations) 314 }) 315 }) 316 }) 317 318 It("serializes into valid swagger JSON", func() { 319 validateSwaggerWithFragments(swagger, [][]byte{ 320 // payload 321 []byte(`"minLength":0`), 322 []byte(`"maxLength":0`), 323 // param 324 []byte(`"minimum":0`), 325 []byte(`"maximum":0`), 326 }) 327 }) 328 }) 329 330 Context("with response templates", func() { 331 const okName = "OK" 332 const okDesc = "OK description" 333 const notFoundName = "NotFound" 334 const notFoundDesc = "NotFound description" 335 const notFoundMt = "application/json" 336 const headerName = "headerName" 337 338 BeforeEach(func() { 339 account := MediaType("application/vnd.goa.test.account", func() { 340 Description("Account") 341 Attributes(func() { 342 Attribute("id", Integer) 343 Attribute("href", String) 344 }) 345 View("default", func() { 346 Attribute("id") 347 Attribute("href") 348 }) 349 View("link", func() { 350 Attribute("id") 351 Attribute("href") 352 }) 353 }) 354 mt := MediaType("application/vnd.goa.test.bottle", func() { 355 Description("A bottle of wine") 356 Attributes(func() { 357 Attribute("id", Integer, "ID of bottle") 358 Attribute("href", String, "API href of bottle") 359 Attribute("account", account, "Owner account") 360 Links(func() { 361 Link("account") // Defines a link to the Account media type 362 }) 363 Required("id", "href") 364 }) 365 View("default", func() { 366 Attribute("id") 367 Attribute("href") 368 Attribute("links") // Default view renders links 369 }) 370 View("extended", func() { 371 Attribute("id") 372 Attribute("href") 373 Attribute("account") // Extended view renders account inline 374 Attribute("links") // Extended view also renders links 375 }) 376 }) 377 base := Design.DSLFunc 378 Design.DSLFunc = func() { 379 base() 380 ResponseTemplate(okName, func() { 381 Description(okDesc) 382 Status(404) 383 Media(mt) 384 Headers(func() { 385 Header(headerName, func() { 386 Format("hostname") 387 }) 388 }) 389 }) 390 ResponseTemplate(notFoundName, func() { 391 Description(notFoundDesc) 392 Status(404) 393 394 Media(notFoundMt) 395 }) 396 } 397 }) 398 399 It("sets the Responses fields", func() { 400 Ω(newErr).ShouldNot(HaveOccurred()) 401 Ω(swagger.Responses).Should(HaveLen(2)) 402 Ω(swagger.Responses[notFoundName]).ShouldNot(BeNil()) 403 Ω(swagger.Responses[notFoundName].Description).Should(Equal(notFoundDesc)) 404 Ω(swagger.Responses[okName]).ShouldNot(BeNil()) 405 Ω(swagger.Responses[okName].Description).Should(Equal(okDesc)) 406 }) 407 408 It("serializes into valid swagger JSON", func() { validateSwagger(swagger) }) 409 }) 410 411 Context("with resources", func() { 412 var ( 413 minLength1 = 1 414 maxLength10 = 10 415 minimum_2 = -2.0 416 maximum2 = 2.0 417 minItems1 = 1 418 maxItems5 = 5 419 ) 420 BeforeEach(func() { 421 Country := MediaType("application/vnd.goa.example.origin", func() { 422 Description("Origin of bottle") 423 Attributes(func() { 424 Attribute("id") 425 Attribute("href") 426 Attribute("country") 427 }) 428 View("default", func() { 429 Attribute("id") 430 Attribute("href") 431 Attribute("country") 432 }) 433 View("tiny", func() { 434 Attribute("id") 435 }) 436 }) 437 BottleMedia := MediaType("application/vnd.goa.example.bottle", func() { 438 Description("A bottle of wine") 439 Attributes(func() { 440 Attribute("id", Integer, "ID of bottle") 441 Attribute("href", String, "API href of bottle") 442 Attribute("origin", Country, "Details on wine origin") 443 Links(func() { 444 Link("origin", "tiny") 445 }) 446 Required("id", "href") 447 }) 448 View("default", func() { 449 Attribute("id") 450 Attribute("href") 451 Attribute("links") 452 }) 453 View("extended", func() { 454 Attribute("id") 455 Attribute("href") 456 Attribute("origin") 457 Attribute("links") 458 }) 459 }) 460 UpdatePayload := Type("UpdatePayload", func() { 461 Description("Type of create and upload action payloads") 462 Attribute("name", String, "name of bottle") 463 Attribute("origin", Country, "Details on wine origin") 464 Required("name") 465 }) 466 Resource("res", func() { 467 Metadata("swagger:tag:res") 468 Description("A wine bottle") 469 DefaultMedia(BottleMedia) 470 BasePath("/bottles") 471 UseTrait("Authenticated") 472 473 Action("Update", func() { 474 Metadata("swagger:tag:Update") 475 Metadata("swagger:summary", "a summary") 476 Description("Update account") 477 Docs(func() { 478 Description("docs") 479 URL("http://cellarapi.com/docs/actions/update") 480 }) 481 Routing( 482 PUT("/:id"), 483 PUT("//orgs/:org/accounts/:id"), 484 ) 485 Params(func() { 486 Param("org", String) 487 Param("id", Integer) 488 Param("sort", func() { 489 Enum("asc", "desc") 490 }) 491 }) 492 Headers(func() { 493 Header("Authorization", String) 494 Header("X-Account", Integer) 495 Header("OptionalBoolWithDefault", Boolean, "defaults true", func() { 496 Default(true) 497 }) 498 Header("OptionalRegex", String, func() { 499 Pattern(`[a-z]\d+`) 500 MinLength(minLength1) 501 MaxLength(maxLength10) 502 }) 503 Header("OptionalInt", Integer, func() { 504 Minimum(minimum_2) 505 Maximum(maximum2) 506 }) 507 Header("OptionalArray", ArrayOf(String), func() { 508 // interpreted as MinItems & MaxItems: 509 MinLength(minItems1) 510 MaxLength(maxItems5) 511 }) 512 Header("OverrideRequiredHeader") 513 Header("OverrideOptionalHeader") 514 Required("Authorization", "X-Account", "OverrideOptionalHeader") 515 }) 516 Payload(UpdatePayload) 517 Response(OK, func() { 518 Media(CollectionOf(BottleMedia), "extended") 519 }) 520 Response(NoContent) 521 Response(NotFound) 522 }) 523 524 Action("hidden", func() { 525 Description("Does not show up in Swagger spec") 526 Metadata("swagger:generate", "false") 527 Routing(GET("/hidden")) 528 Response(OK) 529 }) 530 }) 531 base := Design.DSLFunc 532 Design.DSLFunc = func() { 533 base() 534 Trait("Authenticated", func() { 535 Headers(func() { 536 Header("header") 537 Header("OverrideRequiredHeader", String, "to be overridden in Action and not marked Required") 538 Header("OverrideOptionalHeader", String, "to be overridden in Action and marked Required") 539 Header("OptionalResourceHeaderWithEnum", func() { 540 Enum("a", "b") 541 }) 542 Required("header", "OverrideRequiredHeader") 543 }) 544 }) 545 } 546 }) 547 548 It("sets the Path fields", func() { 549 Ω(newErr).ShouldNot(HaveOccurred()) 550 Ω(swagger.Paths).Should(HaveLen(2)) 551 Ω(swagger.Paths["/orgs/{org}/accounts/{id}"]).ShouldNot(BeNil()) 552 a := swagger.Paths["/orgs/{org}/accounts/{id}"].(*genswagger.Path) 553 Ω(a.Put).ShouldNot(BeNil()) 554 ps := a.Put.Parameters 555 Ω(ps).Should(HaveLen(14)) 556 // check Headers in detail 557 Ω(ps[3]).Should(Equal(&genswagger.Parameter{In: "header", Name: "Authorization", Type: "string", Required: true})) 558 Ω(ps[4]).Should(Equal(&genswagger.Parameter{In: "header", Name: "OptionalArray", Type: "array", CollectionFormat: "multi", 559 Items: &genswagger.Items{Type: "string"}, MinItems: &minItems1, MaxItems: &maxItems5})) 560 Ω(ps[5]).Should(Equal(&genswagger.Parameter{In: "header", Name: "OptionalBoolWithDefault", Type: "boolean", 561 Description: "defaults true", Default: true})) 562 Ω(ps[6]).Should(Equal(&genswagger.Parameter{In: "header", Name: "OptionalInt", Type: "integer", Minimum: &minimum_2, Maximum: &maximum2})) 563 Ω(ps[7]).Should(Equal(&genswagger.Parameter{In: "header", Name: "OptionalRegex", Type: "string", 564 Pattern: `[a-z]\d+`, MinLength: &minLength1, MaxLength: &maxLength10})) 565 Ω(ps[8]).Should(Equal(&genswagger.Parameter{In: "header", Name: "OptionalResourceHeaderWithEnum", Type: "string", 566 Enum: []interface{}{"a", "b"}})) 567 Ω(ps[9]).Should(Equal(&genswagger.Parameter{In: "header", Name: "OverrideOptionalHeader", Type: "string", Required: true})) 568 Ω(ps[10]).Should(Equal(&genswagger.Parameter{In: "header", Name: "OverrideRequiredHeader", Type: "string", Required: true})) 569 Ω(ps[11]).Should(Equal(&genswagger.Parameter{In: "header", Name: "X-Account", Type: "integer", Required: true})) 570 Ω(ps[12]).Should(Equal(&genswagger.Parameter{In: "header", Name: "header", Type: "string", Required: true})) 571 Ω(swagger.Paths["/base/bottles/{id}"]).ShouldNot(BeNil()) 572 b := swagger.Paths["/base/bottles/{id}"].(*genswagger.Path) 573 Ω(b.Put).ShouldNot(BeNil()) 574 Ω(b.Put.Parameters).Should(HaveLen(14)) 575 Ω(b.Put.Produces).Should(Equal([]string{"application/vnd.goa.example.bottle; type=collection"})) 576 }) 577 578 It("should set the inherited tag and the action tag", func() { 579 tags := []string{"res", "Update"} 580 a := swagger.Paths["/orgs/{org}/accounts/{id}"].(*genswagger.Path) 581 Ω(a.Put).ShouldNot(BeNil()) 582 Ω(a.Put.Tags).Should(Equal(tags)) 583 b := swagger.Paths["/base/bottles/{id}"].(*genswagger.Path) 584 Ω(b.Put.Tags).Should(Equal(tags)) 585 }) 586 587 It("sets the summary from the summary tag", func() { 588 a := swagger.Paths["/orgs/{org}/accounts/{id}"].(*genswagger.Path) 589 Ω(a.Put.Summary).Should(Equal("a summary")) 590 }) 591 592 It("generates the media type collection schema", func() { 593 Ω(swagger.Definitions).Should(HaveLen(6)) 594 Ω(swagger.Definitions).Should(HaveKey("GoaExampleBottleExtendedCollection")) 595 }) 596 597 It("serializes into valid swagger JSON", func() { validateSwagger(swagger) }) 598 }) 599 600 Context("with metadata", func() { 601 const gat = "gat" 602 const extension = `{"foo":"bar"}` 603 const stringExtension = "foo" 604 605 var ( 606 unmarshaled map[string]interface{} 607 _ = json.Unmarshal([]byte(extension), &unmarshaled) 608 ) 609 610 BeforeEach(func() { 611 Resource("res", func() { 612 Metadata("swagger:tag:res") 613 Metadata("struct:tag:json", "resource") 614 Metadata("swagger:extension:x-resource", extension) 615 Metadata("swagger:extension:x-string", stringExtension) 616 Action("act", func() { 617 Metadata("swagger:tag:Update") 618 Metadata("struct:tag:json", "action") 619 Metadata("swagger:extension:x-action", extension) 620 Security("password", func() { 621 Metadata("swagger:extension:x-security", extension) 622 }) 623 Routing( 624 PUT("/", func() { 625 Metadata("swagger:extension:x-put", extension) 626 }), 627 ) 628 Params(func() { 629 Param("param", func() { 630 Metadata("swagger:extension:x-param", extension) 631 }) 632 }) 633 Response(NoContent, func() { 634 Metadata("swagger:extension:x-response", extension) 635 }) 636 }) 637 }) 638 base := Design.DSLFunc 639 Design.DSLFunc = func() { 640 base() 641 Metadata("swagger:tag:" + gat) 642 Metadata("struct:tag:json", "api") 643 Metadata("swagger:extension:x-api", extension) 644 BasicAuthSecurity("password") 645 } 646 }) 647 648 It("should set the swagger object tags", func() { 649 Ω(swagger.Tags).Should(HaveLen(2)) 650 tags := []*genswagger.Tag{ 651 {Name: gat, Description: "", ExternalDocs: nil, Extensions: map[string]interface{}{"x-api": unmarshaled}}, 652 {Name: tag, Description: "Tag desc.", ExternalDocs: &genswagger.ExternalDocs{URL: "http://example.com/tag", Description: "Huge docs"}, Extensions: map[string]interface{}{"x-api": unmarshaled}}, 653 } 654 Ω(swagger.Tags).Should(Equal(tags)) 655 }) 656 657 It("should set the action tags", func() { 658 p := swagger.Paths[""].(*genswagger.Path) 659 Ω(p.Put.Tags).Should(HaveLen(2)) 660 tags := []string{"res", "Update"} 661 Ω(p.Put.Tags).Should(Equal(tags)) 662 }) 663 664 It("should set the swagger extensions", func() { 665 Ω(swagger.Info.Extensions).Should(HaveLen(1)) 666 Ω(swagger.Info.Extensions["x-api"]).Should(Equal(unmarshaled)) 667 p := swagger.Paths[""].(*genswagger.Path) 668 Ω(p.Extensions).Should(HaveLen(1)) 669 Ω(p.Extensions["x-action"]).Should(Equal(unmarshaled)) 670 Ω(p.Put.Extensions).Should(HaveLen(1)) 671 Ω(p.Put.Extensions["x-put"]).Should(Equal(unmarshaled)) 672 Ω(p.Put.Parameters[0].Extensions).Should(HaveLen(1)) 673 Ω(p.Put.Parameters[0].Extensions["x-param"]).Should(Equal(unmarshaled)) 674 Ω(p.Put.Responses["204"].Extensions).Should(HaveLen(1)) 675 Ω(p.Put.Responses["204"].Extensions["x-response"]).Should(Equal(unmarshaled)) 676 Ω(swagger.Paths["x-resource"]).ShouldNot(BeNil()) 677 rs := swagger.Paths["x-resource"].(map[string]interface{}) 678 Ω(rs).Should(Equal(unmarshaled)) 679 rs2 := swagger.Paths["x-string"].(string) 680 Ω(rs2).Should(Equal(stringExtension)) 681 Ω(swagger.SecurityDefinitions["password"].Extensions).Should(HaveLen(1)) 682 Ω(swagger.SecurityDefinitions["password"].Extensions["x-security"]).Should(Equal(unmarshaled)) 683 }) 684 685 }) 686 }) 687 })