github.com/emreu/go-swagger@v0.22.1/codescan/application_test.go (about) 1 package codescan 2 3 import ( 4 "sort" 5 "testing" 6 7 "github.com/go-openapi/spec" 8 9 "github.com/stretchr/testify/assert" 10 11 "github.com/stretchr/testify/require" 12 ) 13 14 var ( 15 petstoreCtx *scanCtx 16 classificationCtx *scanCtx 17 ) 18 19 func loadPetstorePkgsCtx(t testing.TB) *scanCtx { 20 if petstoreCtx != nil { 21 return petstoreCtx 22 } 23 sctx, err := newScanCtx(&Options{ 24 Packages: []string{"github.com/go-swagger/go-swagger/fixtures/goparsing/petstore/..."}, 25 }) 26 require.NoError(t, err) 27 petstoreCtx = sctx 28 return petstoreCtx 29 } 30 31 func loadClassificationPkgsCtx(t testing.TB, extra ...string) *scanCtx { 32 if classificationCtx != nil { 33 return classificationCtx 34 } 35 sctx, err := newScanCtx(&Options{ 36 Packages: append([]string{ 37 "github.com/go-swagger/go-swagger/fixtures/goparsing/classification", 38 "github.com/go-swagger/go-swagger/fixtures/goparsing/classification/models", 39 "github.com/go-swagger/go-swagger/fixtures/goparsing/classification/operations", 40 }, extra...), 41 }) 42 require.NoError(t, err) 43 classificationCtx = sctx 44 return classificationCtx 45 } 46 47 func TestApplication_LoadCode(t *testing.T) { 48 sctx := loadClassificationPkgsCtx(t) 49 require.NotNil(t, sctx) 50 require.Len(t, sctx.app.Models, 30) 51 require.Len(t, sctx.app.Meta, 1) 52 require.Len(t, sctx.app.Routes, 7) 53 require.Empty(t, sctx.app.Operations) 54 require.Len(t, sctx.app.Parameters, 10) 55 require.Len(t, sctx.app.Responses, 11) 56 } 57 58 func TestAppScanner_NewSpec(t *testing.T) { 59 doc, err := Run(&Options{ 60 Packages: []string{"github.com/go-swagger/go-swagger/fixtures/goparsing/petstore/..."}, 61 }) 62 require.NoError(t, err) 63 if assert.NotNil(t, doc) { 64 // b, _ := json.MarshalIndent(doc.Responses, "", " ") 65 // log.Println(string(b)) 66 verifyParsedPetStore(t, doc) 67 } 68 } 69 70 func TestAppScanner_Definitions(t *testing.T) { 71 doc, err := Run(&Options{ 72 Packages: []string{"github.com/go-swagger/go-swagger/fixtures/goparsing/bookings/..."}, 73 ScanModels: true, 74 }) 75 require.NoError(t, err) 76 if assert.NotNil(t, doc) { 77 _, ok := doc.Definitions["Booking"] 78 assert.True(t, ok, "Should include cross repo structs") 79 _, ok = doc.Definitions["Customer"] 80 assert.True(t, ok, "Should include package structs with swagger:model") 81 _, ok = doc.Definitions["DateRange"] 82 assert.True(t, ok, "Should include package structs that are used in responses") 83 _, ok = doc.Definitions["BookingResponse"] 84 assert.False(t, ok, "Should not include responses") 85 _, ok = doc.Definitions["IgnoreMe"] 86 assert.False(t, ok, "Should not include un-annotated/un-referenced structs") 87 } 88 } 89 90 func verifyParsedPetStore(t testing.TB, doc *spec.Swagger) { 91 assert.EqualValues(t, []string{"application/json"}, doc.Consumes) 92 assert.EqualValues(t, []string{"application/json"}, doc.Produces) 93 assert.EqualValues(t, []string{"http", "https"}, doc.Schemes) 94 assert.Equal(t, "localhost", doc.Host) 95 assert.Equal(t, "/v2", doc.BasePath) 96 97 verifyInfo(t, doc.Info) 98 99 if assert.NotNil(t, doc.Paths) { 100 assert.Len(t, doc.Paths.Paths, 5) 101 } 102 var keys []string 103 for k := range doc.Definitions { 104 keys = append(keys, k) 105 } 106 assert.Len(t, keys, 3) 107 assert.Len(t, doc.Responses, 4) 108 109 definitions := doc.Definitions 110 mod, ok := definitions["tag"] 111 assert.True(t, ok) 112 assert.Equal(t, spec.StringOrArray([]string{"object"}), mod.Type) 113 assert.Equal(t, "A Tag is an extra piece of data to provide more information about a pet.", mod.Title) 114 assert.Equal(t, "It is used to describe the animals available in the store.", mod.Description) 115 assert.Len(t, mod.Required, 2) 116 117 assertProperty(t, &mod, "integer", "id", "int64", "ID") 118 prop, ok := mod.Properties["id"] 119 assert.True(t, ok, "should have had an 'id' property") 120 assert.Equal(t, "The id of the tag.", prop.Description) 121 122 assertProperty(t, &mod, "string", "value", "", "Value") 123 prop, ok = mod.Properties["value"] 124 assert.True(t, ok) 125 assert.Equal(t, "The value of the tag.", prop.Description) 126 127 mod, ok = definitions["pet"] 128 assert.True(t, ok) 129 assert.Equal(t, spec.StringOrArray([]string{"object"}), mod.Type) 130 assert.Equal(t, "A Pet is the main product in the store.", mod.Title) 131 assert.Equal(t, "It is used to describe the animals available in the store.", mod.Description) 132 assert.Len(t, mod.Required, 2) 133 134 assertProperty(t, &mod, "integer", "id", "int64", "ID") 135 prop, ok = mod.Properties["id"] 136 assert.True(t, ok, "should have had an 'id' property") 137 assert.Equal(t, "The id of the pet.", prop.Description) 138 139 assertProperty(t, &mod, "string", "name", "", "Name") 140 prop, ok = mod.Properties["name"] 141 assert.True(t, ok) 142 assert.Equal(t, "The name of the pet.", prop.Description) 143 assert.EqualValues(t, 3, *prop.MinLength) 144 assert.EqualValues(t, 50, *prop.MaxLength) 145 assert.Equal(t, "\\w[\\w-]+", prop.Pattern) 146 147 assertArrayProperty(t, &mod, "string", "photoUrls", "", "PhotoURLs") 148 prop, ok = mod.Properties["photoUrls"] 149 assert.True(t, ok) 150 assert.Equal(t, "The photo urls for the pet.\nThis only accepts jpeg or png images.", prop.Description) 151 if assert.NotNil(t, prop.Items) && assert.NotNil(t, prop.Items.Schema) { 152 assert.Equal(t, "\\.(jpe?g|png)$", prop.Items.Schema.Pattern) 153 } 154 155 assertProperty(t, &mod, "string", "status", "", "Status") 156 prop, ok = mod.Properties["status"] 157 assert.True(t, ok) 158 assert.Equal(t, "The current status of the pet in the store.", prop.Description) 159 160 assertProperty(t, &mod, "string", "birthday", "date", "Birthday") 161 prop, ok = mod.Properties["birthday"] 162 assert.True(t, ok) 163 assert.Equal(t, "The pet's birthday", prop.Description) 164 165 assertArrayRef(t, &mod, "tags", "Tags", "#/definitions/tag") 166 prop, ok = mod.Properties["tags"] 167 assert.True(t, ok) 168 assert.Equal(t, "Extra bits of information attached to this pet.", prop.Description) 169 170 mod, ok = definitions["order"] 171 assert.True(t, ok) 172 assert.Len(t, mod.Properties, 4) 173 assert.Len(t, mod.Required, 3) 174 175 assertProperty(t, &mod, "integer", "id", "int64", "ID") 176 prop, ok = mod.Properties["id"] 177 assert.True(t, ok, "should have had an 'id' property") 178 assert.Equal(t, "the ID of the order", prop.Description) 179 180 assertProperty(t, &mod, "integer", "userId", "int64", "UserID") 181 prop, ok = mod.Properties["userId"] 182 assert.True(t, ok, "should have had an 'userId' property") 183 assert.Equal(t, "the id of the user who placed the order.", prop.Description) 184 185 assertProperty(t, &mod, "string", "orderedAt", "date-time", "OrderedAt") 186 prop, ok = mod.Properties["orderedAt"] 187 assert.Equal(t, "the time at which this order was made.", prop.Description) 188 assert.True(t, ok, "should have an 'orderedAt' property") 189 190 assertArrayProperty(t, &mod, "object", "items", "", "Items") 191 prop, ok = mod.Properties["items"] 192 assert.True(t, ok, "should have an 'items' slice") 193 assert.NotNil(t, prop.Items, "items should have had an items property") 194 assert.NotNil(t, prop.Items.Schema, "items.items should have had a schema property") 195 196 itprop := prop.Items.Schema 197 assert.Len(t, itprop.Properties, 2) 198 assert.Len(t, itprop.Required, 2) 199 200 assertProperty(t, itprop, "integer", "petId", "int64", "PetID") 201 iprop, ok := itprop.Properties["petId"] 202 assert.True(t, ok, "should have had a 'petId' property") 203 assert.Equal(t, "the id of the pet to order", iprop.Description) 204 205 assertProperty(t, itprop, "integer", "qty", "int32", "Quantity") 206 iprop, ok = itprop.Properties["qty"] 207 assert.True(t, ok, "should have had a 'qty' property") 208 assert.Equal(t, "the quantity of this pet to order", iprop.Description) 209 assert.EqualValues(t, 1, *iprop.Minimum) 210 211 // responses 212 resp, ok := doc.Responses["genericError"] 213 assert.True(t, ok) 214 assert.NotNil(t, resp.Schema) 215 assert.Len(t, resp.Schema.Properties, 2) 216 assertProperty(t, resp.Schema, "integer", "code", "int32", "Code") 217 assertProperty(t, resp.Schema, "string", "message", "", "Message") 218 219 resp, ok = doc.Responses["validationError"] 220 assert.True(t, ok) 221 assert.NotNil(t, resp.Schema) 222 assert.Len(t, resp.Schema.Properties, 3) 223 assertProperty(t, resp.Schema, "integer", "code", "int32", "Code") 224 assertProperty(t, resp.Schema, "string", "message", "", "Message") 225 assertProperty(t, resp.Schema, "string", "field", "", "Field") 226 227 resp, ok = doc.Responses["MarkdownRender"] 228 assert.True(t, ok) 229 assert.NotNil(t, resp.Schema) 230 assert.True(t, resp.Schema.Type.Contains("string")) 231 232 paths := doc.Paths.Paths 233 234 // path /pets 235 op, ok := paths["/pets"] 236 assert.True(t, ok) 237 assert.NotNil(t, op) 238 239 // listPets 240 assert.NotNil(t, op.Get) 241 assert.Equal(t, "Lists the pets known to the store.", op.Get.Summary) 242 assert.Equal(t, "By default it will only lists pets that are available for sale.\nThis can be changed with the status flag.", op.Get.Description) 243 assert.Equal(t, "listPets", op.Get.ID) 244 assert.EqualValues(t, []string{"pets"}, op.Get.Tags) 245 assert.True(t, op.Get.Deprecated) 246 var names namedParams 247 for i, v := range op.Get.Parameters { 248 names = append(names, namedParam{Index: i, Name: v.Name}) 249 } 250 sort.Sort(names) 251 sparam := op.Get.Parameters[names[1].Index] 252 assert.Equal(t, "Status", sparam.Description) 253 assert.Equal(t, "query", sparam.In) 254 assert.Equal(t, "string", sparam.Type) 255 assert.Equal(t, "", sparam.Format) 256 assert.False(t, sparam.Required) 257 assert.Equal(t, "Status", sparam.Extensions["x-go-name"]) 258 assert.Equal(t, "#/responses/genericError", op.Get.Responses.Default.Ref.String()) 259 assert.Len(t, op.Get.Parameters, 2) 260 sparam1 := op.Get.Parameters[names[0].Index] 261 assert.Equal(t, "Birthday", sparam1.Description) 262 assert.Equal(t, "query", sparam1.In) 263 assert.Equal(t, "string", sparam1.Type) 264 assert.Equal(t, "date", sparam1.Format) 265 assert.False(t, sparam1.Required) 266 assert.Equal(t, "Birthday", sparam1.Extensions["x-go-name"]) 267 rs, ok := op.Get.Responses.StatusCodeResponses[200] 268 assert.True(t, ok) 269 assert.NotNil(t, rs.Schema) 270 aprop := rs.Schema 271 assert.Equal(t, "array", aprop.Type[0]) 272 assert.NotNil(t, aprop.Items) 273 assert.NotNil(t, aprop.Items.Schema) 274 assert.Equal(t, "#/definitions/pet", aprop.Items.Schema.Ref.String()) 275 276 // createPet 277 assert.NotNil(t, op.Post) 278 assert.Equal(t, "Creates a new pet in the store.", op.Post.Summary) 279 assert.Equal(t, "", op.Post.Description) 280 assert.Equal(t, "createPet", op.Post.ID) 281 assert.EqualValues(t, []string{"pets"}, op.Post.Tags) 282 verifyRefParam(t, op.Post.Parameters[0], "The pet to submit.", "pet") 283 assert.Equal(t, "#/responses/genericError", op.Post.Responses.Default.Ref.String()) 284 rs, ok = op.Post.Responses.StatusCodeResponses[200] 285 assert.True(t, ok) 286 assert.NotNil(t, rs.Schema) 287 aprop = rs.Schema 288 assert.Equal(t, "#/definitions/pet", aprop.Ref.String()) 289 290 // path /pets/{id} 291 op, ok = paths["/pets/{id}"] 292 assert.True(t, ok) 293 assert.NotNil(t, op) 294 295 // getPetById 296 assert.NotNil(t, op.Get) 297 assert.Equal(t, "Gets the details for a pet.", op.Get.Summary) 298 assert.Equal(t, "", op.Get.Description) 299 assert.Equal(t, "getPetById", op.Get.ID) 300 assert.EqualValues(t, []string{"pets"}, op.Get.Tags) 301 verifyIDParam(t, op.Get.Parameters[0], "The ID of the pet") 302 assert.Equal(t, "#/responses/genericError", op.Get.Responses.Default.Ref.String()) 303 rs, ok = op.Get.Responses.StatusCodeResponses[200] 304 assert.True(t, ok) 305 assert.NotNil(t, rs.Schema) 306 aprop = rs.Schema 307 assert.Equal(t, "#/definitions/pet", aprop.Ref.String()) 308 309 // updatePet 310 assert.NotNil(t, op.Put) 311 assert.Equal(t, "Updates the details for a pet.", op.Put.Summary) 312 assert.Equal(t, "", op.Put.Description) 313 assert.Equal(t, "updatePet", op.Put.ID) 314 assert.EqualValues(t, []string{"pets"}, op.Put.Tags) 315 verifyIDParam(t, op.Put.Parameters[0], "The ID of the pet") 316 verifyRefParam(t, op.Put.Parameters[1], "The pet to submit.", "pet") 317 assert.Equal(t, "#/responses/genericError", op.Put.Responses.Default.Ref.String()) 318 rs, ok = op.Put.Responses.StatusCodeResponses[200] 319 assert.True(t, ok) 320 assert.NotNil(t, rs.Schema) 321 aprop = rs.Schema 322 assert.Equal(t, "#/definitions/pet", aprop.Ref.String()) 323 324 // deletePet 325 assert.NotNil(t, op.Delete) 326 assert.Equal(t, "Deletes a pet from the store.", op.Delete.Summary) 327 assert.Equal(t, "", op.Delete.Description) 328 assert.Equal(t, "deletePet", op.Delete.ID) 329 assert.EqualValues(t, []string{"pets"}, op.Delete.Tags) 330 verifyIDParam(t, op.Delete.Parameters[0], "The ID of the pet") 331 assert.Equal(t, "#/responses/genericError", op.Delete.Responses.Default.Ref.String()) 332 _, ok = op.Delete.Responses.StatusCodeResponses[204] 333 assert.True(t, ok) 334 335 // path /orders/{id} 336 op, ok = paths["/orders/{id}"] 337 assert.True(t, ok) 338 assert.NotNil(t, op) 339 340 // getOrderDetails 341 assert.NotNil(t, op.Get) 342 assert.Equal(t, "Gets the details for an order.", op.Get.Summary) 343 assert.Equal(t, "", op.Get.Description) 344 assert.Equal(t, "getOrderDetails", op.Get.ID) 345 assert.EqualValues(t, []string{"orders"}, op.Get.Tags) 346 verifyIDParam(t, op.Get.Parameters[0], "The ID of the order") 347 assert.Equal(t, "#/responses/genericError", op.Get.Responses.Default.Ref.String()) 348 rs, ok = op.Get.Responses.StatusCodeResponses[200] 349 assert.True(t, ok) 350 assert.Equal(t, "#/responses/orderResponse", rs.Ref.String()) 351 rsm := doc.Responses["orderResponse"] 352 assert.NotNil(t, rsm.Schema) 353 assert.Equal(t, "#/definitions/order", rsm.Schema.Ref.String()) 354 355 // cancelOrder 356 assert.NotNil(t, op.Delete) 357 assert.Equal(t, "Deletes an order.", op.Delete.Summary) 358 assert.Equal(t, "", op.Delete.Description) 359 assert.Equal(t, "cancelOrder", op.Delete.ID) 360 assert.EqualValues(t, []string{"orders"}, op.Delete.Tags) 361 verifyIDParam(t, op.Delete.Parameters[0], "The ID of the order") 362 assert.Equal(t, "#/responses/genericError", op.Delete.Responses.Default.Ref.String()) 363 _, ok = op.Delete.Responses.StatusCodeResponses[204] 364 assert.True(t, ok) 365 366 // updateOrder 367 assert.NotNil(t, op.Put) 368 assert.Equal(t, "Updates an order.", op.Put.Summary) 369 assert.Equal(t, "", op.Put.Description) 370 assert.Equal(t, "updateOrder", op.Put.ID) 371 assert.EqualValues(t, []string{"orders"}, op.Put.Tags) 372 verifyIDParam(t, op.Put.Parameters[0], "The ID of the order") 373 verifyRefParam(t, op.Put.Parameters[1], "The order to submit", "order") 374 assert.Equal(t, "#/responses/genericError", op.Put.Responses.Default.Ref.String()) 375 rs, ok = op.Put.Responses.StatusCodeResponses[200] 376 assert.True(t, ok) 377 assert.NotNil(t, rs.Schema) 378 aprop = rs.Schema 379 assert.Equal(t, "#/definitions/order", aprop.Ref.String()) 380 381 // path /orders 382 op, ok = paths["/orders"] 383 assert.True(t, ok) 384 assert.NotNil(t, op) 385 386 // createOrder 387 assert.NotNil(t, op.Post) 388 assert.Equal(t, "Creates an order.", op.Post.Summary) 389 assert.Equal(t, "", op.Post.Description) 390 assert.Equal(t, "createOrder", op.Post.ID) 391 assert.EqualValues(t, []string{"orders"}, op.Post.Tags) 392 verifyRefParam(t, op.Post.Parameters[0], "The order to submit", "order") 393 assert.Equal(t, "#/responses/genericError", op.Post.Responses.Default.Ref.String()) 394 rs, ok = op.Post.Responses.StatusCodeResponses[200] 395 assert.True(t, ok) 396 assert.Equal(t, "#/responses/orderResponse", rs.Ref.String()) 397 rsm = doc.Responses["orderResponse"] 398 assert.NotNil(t, rsm.Schema) 399 assert.Equal(t, "#/definitions/order", rsm.Schema.Ref.String()) 400 } 401 402 func verifyIDParam(t testing.TB, param spec.Parameter, description string) { 403 assert.Equal(t, description, param.Description) 404 assert.Equal(t, "path", param.In) 405 assert.Equal(t, "integer", param.Type) 406 assert.Equal(t, "int64", param.Format) 407 assert.True(t, param.Required) 408 assert.Equal(t, "ID", param.Extensions["x-go-name"]) 409 } 410 411 func verifyRefParam(t testing.TB, param spec.Parameter, description, refed string) { 412 assert.Equal(t, description, param.Description) 413 assert.Equal(t, "body", param.In) 414 // TODO: this may fail sometimes (seen on go1.12 windows test): require pointer to be valid and avoid panicking 415 require.NotNil(t, param) 416 require.NotNil(t, param.Schema) 417 assert.Equal(t, "#/definitions/"+refed, param.Schema.Ref.String()) 418 assert.True(t, param.Required) 419 } 420 421 type namedParam struct { 422 Index int 423 Name string 424 } 425 426 type namedParams []namedParam 427 428 func (g namedParams) Len() int { return len(g) } 429 func (g namedParams) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 430 func (g namedParams) Less(i, j int) bool { return g[i].Name < g[j].Name }