From 00396f4fb07e5fd7339e50eba621656093e80128 Mon Sep 17 00:00:00 2001 From: martincostello Date: Thu, 8 Aug 2024 14:07:44 +0100 Subject: [PATCH] Fix verification tests Fix missing verification tests for the Basic website. --- ...lidSwaggerJson_Basic_DotNet_6.verified.txt | 1449 +++++++++++++++++ ...lidSwaggerJson_Basic_DotNet_8.verified.txt | 1448 ++++++++++++++++ .../SwaggerVerifyIntegrationTest.cs | 38 +- 3 files changed, 2932 insertions(+), 3 deletions(-) create mode 100644 test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_6.verified.txt create mode 100644 test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_8.verified.txt diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_6.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_6.verified.txt new file mode 100644 index 0000000000..83ff3be810 --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_6.verified.txt @@ -0,0 +1,1449 @@ +{ + openapi: 3.0.1, + info: { + title: Test API V1, + description: A sample API for testing Swashbuckle, + termsOfService: http://tempuri.org/terms, + version: v1 + }, + paths: { + /products: { + post: { + tags: [ + CrudActions + ], + summary: Creates a product, + description: +## Heading 1 + + POST /products + { + "id": "123", + "description": "Some product" + }, + operationId: CreateProduct, + requestBody: { + description: , + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/Product + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + } + } + } + }, + x-purpose: test + }, + get: { + tags: [ + CrudActions + ], + summary: Searches the collection of products by description key words, + operationId: SearchProducts, + parameters: [ + { + name: kw, + in: query, + description: A list of search terms, + schema: { + type: string, + default: foobar + }, + example: hello + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: array, + items: { + $ref: #/components/schemas/Product + } + } + } + } + } + }, + x-purpose: test + } + }, + /products/{id}: { + get: { + tags: [ + CrudActions + ], + summary: Returns a specific product, + operationId: GetProduct, + parameters: [ + { + name: id, + in: path, + description: The product id, + required: true, + schema: { + type: integer, + format: int32 + }, + example: 111 + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + } + } + } + }, + x-purpose: test + }, + put: { + tags: [ + CrudActions + ], + summary: Updates all properties of a specific product, + operationId: UpdateProduct, + parameters: [ + { + name: id, + in: path, + description: , + required: true, + schema: { + type: integer, + format: int32 + }, + example: 222 + } + ], + requestBody: { + description: , + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/Product + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + }, + patch: { + tags: [ + CrudActions + ], + summary: Updates some properties of a specific product, + operationId: PatchProduct, + parameters: [ + { + name: id, + in: path, + description: , + required: true, + schema: { + type: integer, + format: int32 + }, + example: 333 + } + ], + requestBody: { + description: , + content: { + application/json: { + schema: { + type: object + } + }, + text/json: { + schema: { + type: object + } + }, + application/*+json: { + schema: { + type: object + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + }, + delete: { + tags: [ + CrudActions + ], + summary: Deletes a specific product, + operationId: DeleteProduct, + parameters: [ + { + name: id, + in: path, + description: , + required: true, + schema: { + type: integer, + format: int32 + }, + example: 444 + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /payments/authorize: { + post: { + tags: [ + DataAnnotations + ], + requestBody: { + content: { + application/json: { + schema: { + $ref: #/components/schemas/PaymentRequest + } + }, + text/json: { + schema: { + $ref: #/components/schemas/PaymentRequest + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/PaymentRequest + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: string + } + } + } + } + }, + x-purpose: test + } + }, + /payments/{paymentId}/cancel: { + put: { + tags: [ + DataAnnotations + ], + parameters: [ + { + name: paymentId, + in: path, + required: true, + schema: { + minLength: 6, + type: string + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /kittens: { + post: { + tags: [ + DynamicTypes + ], + requestBody: { + content: { + application/json: {}, + text/json: {}, + application/*+json: {} + }, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: integer, + format: int32 + } + } + } + } + }, + x-purpose: test + } + }, + /unicorns: { + get: { + tags: [ + DynamicTypes + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: object + } + } + } + } + }, + x-purpose: test + } + }, + /dragons: { + post: { + tags: [ + DynamicTypes + ], + requestBody: { + content: { + application/json: {}, + text/json: {}, + application/*+json: {} + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/single: { + post: { + tags: [ + Files + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + file: { + type: string, + format: binary + } + } + }, + encoding: { + file: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/multiple: { + post: { + tags: [ + Files + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + files: { + type: array, + items: { + type: string, + format: binary + } + } + } + }, + encoding: { + files: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/form-with-file: { + post: { + tags: [ + Files + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + name: { + type: string + }, + file: { + type: string, + format: binary + } + } + }, + encoding: { + name: { + style: form + }, + file: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/{name}: { + get: { + tags: [ + Files + ], + parameters: [ + { + name: name, + in: path, + required: true, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + oneOf: [ + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + } + ] + } + }, + application/zip: { + schema: { + oneOf: [ + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + } + ] + } + } + } + } + }, + x-purpose: test + } + }, + /registrations: { + post: { + tags: [ + FromFormParams + ], + requestBody: { + content: { + application/x-www-form-urlencoded: { + schema: { + type: object, + properties: { + name: { + type: string + }, + phoneNumbers: { + type: array, + items: { + type: integer, + format: int32 + } + } + } + }, + encoding: { + name: { + style: form + }, + phoneNumbers: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /registrationsWithIgnoreProperties: { + post: { + tags: [ + FromFormParams + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + phoneNumbers: { + type: array, + items: { + type: integer, + format: int32 + } + } + } + }, + encoding: { + phoneNumbers: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /country/validate: { + get: { + tags: [ + FromHeaderParams + ], + parameters: [ + { + name: country, + in: query, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /addresses/validate: { + get: { + tags: [ + FromQueryParams + ], + parameters: [ + { + name: country, + in: query, + description: 3-letter ISO country code, + required: true, + schema: { + type: string + } + }, + { + name: city, + in: query, + description: Name of city, + schema: { + type: string, + default: Seattle + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /zip-codes/validate: { + get: { + tags: [ + FromQueryParams + ], + parameters: [ + { + name: zipCodes, + in: query, + schema: { + type: array, + items: { + type: string + } + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /promotions: { + get: { + tags: [ + JsonAnnotations + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: array, + items: { + $ref: #/components/schemas/Promotion + } + } + } + } + } + }, + x-purpose: test + } + }, + /shapes: { + post: { + tags: [ + PolymorphicTypes + ], + requestBody: { + content: { + application/json: { + schema: { + oneOf: [ + null, + null + ] + } + }, + text/json: { + schema: { + oneOf: [ + null, + null + ] + } + }, + application/*+json: { + schema: { + oneOf: [ + null, + null + ] + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + type: integer, + format: int32 + } + }, + application/json: { + schema: { + type: integer, + format: int32 + } + }, + text/json: { + schema: { + type: integer, + format: int32 + } + } + } + } + }, + x-purpose: test + } + }, + /orders: { + post: { + tags: [ + ResponseTypeAnnotations + ], + summary: Creates an order, + requestBody: { + description: , + content: { + application/xml: { + schema: { + $ref: #/components/schemas/Order + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 201: { + description: Order created, + content: { + application/xml: { + schema: { + type: integer, + format: int32 + } + } + } + }, + 400: { + description: Order invalid, + content: { + application/xml: { + schema: { + $ref: #/components/schemas/ValidationProblemDetails + } + } + } + } + }, + x-purpose: test + } + }, + /carts: { + post: { + tags: [ + SwaggerAnnotations + ], + operationId: CreateCart, + requestBody: { + description: The cart request body, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/Cart + } + } + }, + x-purpose: test + }, + responses: { + 201: { + description: The cart was created, + content: { + text/plain: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + } + } + }, + 400: { + description: The cart data is invalid + } + }, + x-purpose: test + } + }, + /carts/{id}: { + get: { + tags: [ + SwaggerAnnotations + ], + externalDocs: { + description: External docs for CartsByIdGet, + url: https://tempuri.org/carts-by-id-get + }, + operationId: GetCart, + parameters: [ + { + name: id, + in: path, + description: The cart identifier, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + } + } + } + }, + x-purpose: test + }, + delete: { + tags: [ + SwaggerAnnotations + ], + summary: Deletes a specific cart, + description: Requires admin privileges, + operationId: DeleteCart, + parameters: [ + { + name: id, + in: path, + description: The cart identifier, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + } + } + } + }, + x-purpose: test + } + }, + /stores: { + post: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: query, + schema: { + type: integer, + format: int32 + } + }, + { + name: location, + in: query, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: integer, + format: int32 + } + } + } + } + }, + x-purpose: test + }, + get: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: locations, + in: query, + schema: { + type: array, + items: { + type: string + } + } + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: array, + items: { + $ref: #/components/schemas/Store + } + } + } + } + } + }, + x-purpose: test + } + }, + /stores/{id}: { + get: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: path, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Store + } + } + } + } + }, + x-purpose: test + }, + put: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: path, + required: true, + schema: { + type: integer, + format: int32 + } + }, + { + name: id, + in: query, + schema: { + type: integer, + format: int32 + } + }, + { + name: location, + in: query, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + }, + delete: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: path, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + } + }, + components: { + schemas: { + Cart: { + required: [ + Id + ], + type: object, + properties: { + id: { + type: integer, + description: The cart identifier, + format: int32, + readOnly: true + }, + cartType: { + $ref: #/components/schemas/CartType + } + }, + additionalProperties: false + }, + CartType: { + enum: [ + 0, + 1 + ], + type: integer, + description: The cart type, + format: int32 + }, + Circle: { + allOf: [ + null, + { + type: object, + properties: { + radius: { + type: integer, + format: int32 + } + }, + additionalProperties: false + } + ] + }, + CreditCard: { + required: [ + cardNumber, + expMonth, + expYear + ], + type: object, + properties: { + cardNumber: { + minLength: 1, + pattern: ^[3-6]?\d{12,15}$, + type: string + }, + expMonth: { + maximum: 12, + minimum: 1, + type: integer, + format: int32 + }, + expYear: { + maximum: 99, + minimum: 14, + type: integer, + format: int32 + } + }, + additionalProperties: false + }, + DiscountType: { + enum: [ + Percentage, + Amount + ], + type: string + }, + Order: { + type: object, + properties: { + id: { + type: integer, + format: int32 + }, + description: { + type: string, + nullable: true + }, + total: { + type: number, + format: double + } + }, + additionalProperties: false + }, + PaymentRequest: { + required: [ + creditCard, + transaction + ], + type: object, + properties: { + transaction: { + $ref: #/components/schemas/Transaction + }, + creditCard: { + $ref: #/components/schemas/CreditCard + } + }, + additionalProperties: false + }, + Product: { + type: object, + properties: { + id: { + type: integer, + description: Uniquely identifies the product, + format: int32 + }, + description: { + type: string, + description: Describes the product, + nullable: true + }, + status: { + $ref: #/components/schemas/ProductStatus + }, + status2: { + $ref: #/components/schemas/ProductStatus + } + }, + additionalProperties: false, + description: Represents a product, + example: { + id: 123, + description: foobar, + price: 14.37 + } + }, + ProductStatus: { + enum: [ + 0, + 1, + 2 + ], + type: integer, + format: int32 + }, + Promotion: { + type: object, + properties: { + promo-code: { + type: string, + nullable: true + }, + discountType: { + $ref: #/components/schemas/DiscountType + } + }, + additionalProperties: false + }, + Rectangle: { + allOf: [ + null, + { + type: object, + properties: { + height: { + type: integer, + format: int32 + }, + width: { + type: integer, + format: int32 + } + }, + additionalProperties: false + } + ] + }, + Shape: { + required: [ + TypeName + ], + type: object, + properties: { + TypeName: { + type: string + }, + name: { + type: string, + nullable: true + } + }, + additionalProperties: false, + discriminator: { + propertyName: TypeName, + mapping: { + Rectangle: #/components/schemas/Rectangle, + Circle: #/components/schemas/Circle + } + } + }, + Store: { + type: object, + properties: { + id: { + type: integer, + format: int32 + }, + location: { + type: string, + nullable: true + } + }, + additionalProperties: false + }, + Transaction: { + required: [ + amount + ], + type: object, + properties: { + amount: { + type: number, + format: double + }, + note: { + type: string, + nullable: true + } + }, + additionalProperties: false + }, + ValidationProblemDetails: { + type: object, + properties: { + type: { + type: string, + nullable: true + }, + title: { + type: string, + nullable: true + }, + status: { + type: integer, + format: int32, + nullable: true + }, + detail: { + type: string, + nullable: true + }, + instance: { + type: string, + nullable: true + }, + errors: { + type: object, + additionalProperties: { + type: array, + items: { + type: string + } + }, + nullable: true, + readOnly: true + } + } + } + } + }, + tags: [ + { + name: SwaggerAnnotations, + description: Manipulate Carts to your heart's content, + externalDocs: { + url: http://www.tempuri.org + } + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_8.verified.txt b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_8.verified.txt new file mode 100644 index 0000000000..07dc53bbcf --- /dev/null +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_8.verified.txt @@ -0,0 +1,1448 @@ +{ + openapi: 3.0.1, + info: { + title: Test API V1, + description: A sample API for testing Swashbuckle, + termsOfService: http://tempuri.org/terms, + version: v1 + }, + paths: { + /products: { + post: { + tags: [ + CrudActions + ], + summary: Creates a product, + description: +## Heading 1 + + POST /products + { + "id": "123", + "description": "Some product" + }, + operationId: CreateProduct, + requestBody: { + description: , + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/Product + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + } + } + } + }, + x-purpose: test + }, + get: { + tags: [ + CrudActions + ], + summary: Searches the collection of products by description key words, + operationId: SearchProducts, + parameters: [ + { + name: kw, + in: query, + description: A list of search terms, + schema: { + type: string, + default: foobar + }, + example: hello + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: array, + items: { + $ref: #/components/schemas/Product + } + } + } + } + } + }, + x-purpose: test + } + }, + /products/{id}: { + get: { + tags: [ + CrudActions + ], + summary: Returns a specific product, + operationId: GetProduct, + parameters: [ + { + name: id, + in: path, + description: The product id, + required: true, + schema: { + type: integer, + format: int32 + }, + example: 111 + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + } + } + } + }, + x-purpose: test + }, + put: { + tags: [ + CrudActions + ], + summary: Updates all properties of a specific product, + operationId: UpdateProduct, + parameters: [ + { + name: id, + in: path, + description: , + required: true, + schema: { + type: integer, + format: int32 + }, + example: 222 + } + ], + requestBody: { + description: , + content: { + application/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Product + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/Product + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + }, + patch: { + tags: [ + CrudActions + ], + summary: Updates some properties of a specific product, + operationId: PatchProduct, + parameters: [ + { + name: id, + in: path, + description: , + required: true, + schema: { + type: integer, + format: int32 + }, + example: 333 + } + ], + requestBody: { + description: , + content: { + application/json: { + schema: { + type: object + } + }, + text/json: { + schema: { + type: object + } + }, + application/*+json: { + schema: { + type: object + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + }, + delete: { + tags: [ + CrudActions + ], + summary: Deletes a specific product, + operationId: DeleteProduct, + parameters: [ + { + name: id, + in: path, + description: , + required: true, + schema: { + type: integer, + format: int32 + }, + example: 444 + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /payments/authorize: { + post: { + tags: [ + DataAnnotations + ], + requestBody: { + content: { + application/json: { + schema: { + $ref: #/components/schemas/PaymentRequest + } + }, + text/json: { + schema: { + $ref: #/components/schemas/PaymentRequest + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/PaymentRequest + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: string + } + } + } + } + }, + x-purpose: test + } + }, + /payments/{paymentId}/cancel: { + put: { + tags: [ + DataAnnotations + ], + parameters: [ + { + name: paymentId, + in: path, + required: true, + schema: { + minLength: 6, + type: string + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /kittens: { + post: { + tags: [ + DynamicTypes + ], + requestBody: { + content: { + application/json: {}, + text/json: {}, + application/*+json: {} + }, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: integer, + format: int32 + } + } + } + } + }, + x-purpose: test + } + }, + /unicorns: { + get: { + tags: [ + DynamicTypes + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: object + } + } + } + } + }, + x-purpose: test + } + }, + /dragons: { + post: { + tags: [ + DynamicTypes + ], + requestBody: { + content: { + application/json: {}, + text/json: {}, + application/*+json: {} + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/single: { + post: { + tags: [ + Files + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + file: { + type: string, + format: binary + } + } + }, + encoding: { + file: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/multiple: { + post: { + tags: [ + Files + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + files: { + type: array, + items: { + type: string, + format: binary + } + } + } + }, + encoding: { + files: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/form-with-file: { + post: { + tags: [ + Files + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + name: { + type: string + }, + file: { + type: string, + format: binary + } + } + }, + encoding: { + name: { + style: form + }, + file: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /files/{name}: { + get: { + tags: [ + Files + ], + parameters: [ + { + name: name, + in: path, + required: true, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + oneOf: [ + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + } + ] + } + }, + application/zip: { + schema: { + oneOf: [ + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + }, + { + type: string, + format: binary + } + ] + } + } + } + } + }, + x-purpose: test + } + }, + /registrations: { + post: { + tags: [ + FromFormParams + ], + requestBody: { + content: { + application/x-www-form-urlencoded: { + schema: { + type: object, + properties: { + name: { + type: string + }, + phoneNumbers: { + type: array, + items: { + type: integer, + format: int32 + } + } + } + }, + encoding: { + name: { + style: form + }, + phoneNumbers: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /registrationsWithIgnoreProperties: { + post: { + tags: [ + FromFormParams + ], + requestBody: { + content: { + multipart/form-data: { + schema: { + type: object, + properties: { + phoneNumbers: { + type: array, + items: { + type: integer, + format: int32 + } + } + } + }, + encoding: { + phoneNumbers: { + style: form + } + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /country/validate: { + get: { + tags: [ + FromHeaderParams + ], + parameters: [ + { + name: country, + in: query, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /addresses/validate: { + get: { + tags: [ + FromQueryParams + ], + parameters: [ + { + name: country, + in: query, + description: 3-letter ISO country code, + required: true, + schema: { + type: string + } + }, + { + name: city, + in: query, + description: Name of city, + schema: { + type: string, + default: Seattle + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /zip-codes/validate: { + get: { + tags: [ + FromQueryParams + ], + parameters: [ + { + name: zipCodes, + in: query, + schema: { + type: array, + items: { + type: string + } + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + }, + /promotions: { + get: { + tags: [ + JsonAnnotations + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: array, + items: { + $ref: #/components/schemas/Promotion + } + } + } + } + } + }, + x-purpose: test + } + }, + /shapes: { + post: { + tags: [ + PolymorphicTypes + ], + requestBody: { + content: { + application/json: { + schema: { + oneOf: [ + null, + null + ] + } + }, + text/json: { + schema: { + oneOf: [ + null, + null + ] + } + }, + application/*+json: { + schema: { + oneOf: [ + null, + null + ] + } + } + }, + x-purpose: test + }, + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + type: integer, + format: int32 + } + }, + application/json: { + schema: { + type: integer, + format: int32 + } + }, + text/json: { + schema: { + type: integer, + format: int32 + } + } + } + } + }, + x-purpose: test + } + }, + /orders: { + post: { + tags: [ + ResponseTypeAnnotations + ], + summary: Creates an order, + requestBody: { + description: , + content: { + application/xml: { + schema: { + $ref: #/components/schemas/Order + } + } + }, + required: true, + x-purpose: test + }, + responses: { + 201: { + description: Order created, + content: { + application/xml: { + schema: { + type: integer, + format: int32 + } + } + } + }, + 400: { + description: Order invalid, + content: { + application/xml: { + schema: { + $ref: #/components/schemas/ValidationProblemDetails + } + } + } + } + }, + x-purpose: test + } + }, + /carts: { + post: { + tags: [ + SwaggerAnnotations + ], + operationId: CreateCart, + requestBody: { + description: The cart request body, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/*+json: { + schema: { + $ref: #/components/schemas/Cart + } + } + }, + x-purpose: test + }, + responses: { + 201: { + description: The cart was created, + content: { + text/plain: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + } + } + }, + 400: { + description: The cart data is invalid + } + }, + x-purpose: test + } + }, + /carts/{id}: { + get: { + tags: [ + SwaggerAnnotations + ], + externalDocs: { + description: External docs for CartsByIdGet, + url: https://tempuri.org/carts-by-id-get + }, + operationId: GetCart, + parameters: [ + { + name: id, + in: path, + description: The cart identifier, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + } + } + } + }, + x-purpose: test + }, + delete: { + tags: [ + SwaggerAnnotations + ], + summary: Deletes a specific cart, + description: Requires admin privileges, + operationId: DeleteCart, + parameters: [ + { + name: id, + in: path, + description: The cart identifier, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK, + content: { + text/plain: { + schema: { + $ref: #/components/schemas/Cart + } + }, + application/json: { + schema: { + $ref: #/components/schemas/Cart + } + }, + text/json: { + schema: { + $ref: #/components/schemas/Cart + } + } + } + } + }, + x-purpose: test + } + }, + /stores: { + post: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: query, + schema: { + type: integer, + format: int32 + } + }, + { + name: location, + in: query, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: integer, + format: int32 + } + } + } + } + }, + x-purpose: test + }, + get: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: locations, + in: query, + schema: { + type: array, + items: { + type: string + } + } + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + type: array, + items: { + $ref: #/components/schemas/Store + } + } + } + } + } + }, + x-purpose: test + } + }, + /stores/{id}: { + get: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: path, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK, + content: { + application/json: { + schema: { + $ref: #/components/schemas/Store + } + } + } + } + }, + x-purpose: test + }, + put: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: query, + schema: { + type: integer, + format: int32 + } + }, + { + name: id, + in: path, + required: true, + schema: { + type: integer, + format: int32 + } + }, + { + name: location, + in: query, + schema: { + type: string + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + }, + delete: { + tags: [ + UnboundParams + ], + parameters: [ + { + name: id, + in: path, + required: true, + schema: { + type: integer, + format: int32 + } + } + ], + responses: { + 200: { + description: OK + } + }, + x-purpose: test + } + } + }, + components: { + schemas: { + Cart: { + required: [ + Id + ], + type: object, + properties: { + id: { + type: integer, + description: The cart identifier, + format: int32, + readOnly: true + }, + cartType: { + $ref: #/components/schemas/CartType + } + }, + additionalProperties: false + }, + CartType: { + enum: [ + 0, + 1 + ], + type: integer, + description: The cart type, + format: int32 + }, + Circle: { + allOf: [ + null, + { + type: object, + properties: { + radius: { + type: integer, + format: int32 + } + }, + additionalProperties: false + } + ] + }, + CreditCard: { + required: [ + cardNumber, + expMonth, + expYear + ], + type: object, + properties: { + cardNumber: { + minLength: 1, + pattern: ^[3-6]?\d{12,15}$, + type: string + }, + expMonth: { + maximum: 12, + minimum: 1, + type: integer, + format: int32 + }, + expYear: { + maximum: 99, + minimum: 14, + type: integer, + format: int32 + } + }, + additionalProperties: false + }, + DiscountType: { + enum: [ + Percentage, + Amount + ], + type: string + }, + Order: { + type: object, + properties: { + id: { + type: integer, + format: int32 + }, + description: { + type: string, + nullable: true + }, + total: { + type: number, + format: double + } + }, + additionalProperties: false + }, + PaymentRequest: { + required: [ + creditCard, + transaction + ], + type: object, + properties: { + transaction: { + $ref: #/components/schemas/Transaction + }, + creditCard: { + $ref: #/components/schemas/CreditCard + } + }, + additionalProperties: false + }, + Product: { + type: object, + properties: { + id: { + type: integer, + description: Uniquely identifies the product, + format: int32 + }, + description: { + type: string, + description: Describes the product, + nullable: true + }, + status: { + $ref: #/components/schemas/ProductStatus + }, + status2: { + $ref: #/components/schemas/ProductStatus + } + }, + additionalProperties: false, + description: Represents a product, + example: { + id: 123, + description: foobar, + price: 14.37 + } + }, + ProductStatus: { + enum: [ + 0, + 1, + 2 + ], + type: integer, + format: int32 + }, + Promotion: { + type: object, + properties: { + promo-code: { + type: string, + nullable: true + }, + discountType: { + $ref: #/components/schemas/DiscountType + } + }, + additionalProperties: false + }, + Rectangle: { + allOf: [ + null, + { + type: object, + properties: { + height: { + type: integer, + format: int32 + }, + width: { + type: integer, + format: int32 + } + }, + additionalProperties: false + } + ] + }, + Shape: { + required: [ + TypeName + ], + type: object, + properties: { + TypeName: { + type: string + }, + name: { + type: string, + nullable: true + } + }, + additionalProperties: false, + discriminator: { + propertyName: TypeName, + mapping: { + Rectangle: #/components/schemas/Rectangle, + Circle: #/components/schemas/Circle + } + } + }, + Store: { + type: object, + properties: { + id: { + type: integer, + format: int32 + }, + location: { + type: string, + nullable: true + } + }, + additionalProperties: false + }, + Transaction: { + required: [ + amount + ], + type: object, + properties: { + amount: { + type: number, + format: double + }, + note: { + type: string, + nullable: true + } + }, + additionalProperties: false + }, + ValidationProblemDetails: { + type: object, + properties: { + type: { + type: string, + nullable: true + }, + title: { + type: string, + nullable: true + }, + status: { + type: integer, + format: int32, + nullable: true + }, + detail: { + type: string, + nullable: true + }, + instance: { + type: string, + nullable: true + }, + errors: { + type: object, + additionalProperties: { + type: array, + items: { + type: string + } + }, + nullable: true + } + } + } + } + }, + tags: [ + { + name: SwaggerAnnotations, + description: Manipulate Carts to your heart's content, + externalDocs: { + url: http://www.tempuri.org + } + } + ] +} \ No newline at end of file diff --git a/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.cs b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.cs index 142969bff3..ca92a7e86c 100644 --- a/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.cs +++ b/test/Swashbuckle.AspNetCore.IntegrationTests/SwaggerVerifyIntegrationTest.cs @@ -9,7 +9,7 @@ namespace Swashbuckle.AspNetCore.IntegrationTests { [Collection("TestSite")] - public class SwaggerVerifyIntegrationTest + public partial class SwaggerVerifyIntegrationTest { [Theory] [InlineData(typeof(CliExample.Startup), "/swagger/v1/swagger_net8.0.json")] @@ -34,7 +34,31 @@ public async Task SwaggerEndpoint_ReturnsValidSwaggerJson( await Verifier.Verify(swagger).UseParameters(startupType, GetVersion(swaggerRequestUri)); } +#if NET6_0 + [Fact] + public async Task SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_6() + { + var testSite = new TestSite(typeof(Basic.Startup)); + using var client = testSite.BuildClient(); + + using var swaggerResponse = await client.GetAsync("/swagger/v1/swagger.json"); + var swagger = await swaggerResponse.Content.ReadAsStringAsync(); + await Verifier.VerifyJson(swagger); + } +#endif + #if NET8_0_OR_GREATER + [Fact] + public async Task SwaggerEndpoint_ReturnsValidSwaggerJson_Basic_DotNet_8() + { + var testSite = new TestSite(typeof(Basic.Startup)); + using var client = testSite.BuildClient(); + + using var swaggerResponse = await client.GetAsync("/swagger/v1/swagger.json"); + var swagger = await swaggerResponse.Content.ReadAsStringAsync(); + await Verifier.VerifyJson(swagger); + } + [Theory] [InlineData("/swagger/v1/swagger.json")] public async Task SwaggerEndpoint_ReturnsValidSwaggerJson_For_WebApi( @@ -71,13 +95,21 @@ private static async Task SwaggerEndpointReturnsValidSwaggerJson SwaggerResponse(HttpClient client, string swaggerRequestUri) { using var swaggerResponse = await client.GetAsync(swaggerRequestUri); var contentStream = await swaggerResponse.Content.ReadAsStringAsync(); return contentStream; } - private static string GetVersion(string swaggerUi) => Regex.Match(swaggerUi, "/\\w+/([\\w+\\d+.-]+)/").Groups[1].Value; +#endif + private static string GetVersion(string swaggerUi) => +#if NET6_0 + Regex.Match(swaggerUi, "/\\w+/([\\w+\\d+.-]+)/").Groups[1].Value; +#else + VersionRegex().Match(swaggerUi).Groups[1].Value; + + [GeneratedRegex("/\\w+/([\\w+\\d+.-]+)/")] + private static partial Regex VersionRegex(); +#endif } }