diff --git a/core/src/main/java/org/openapitools/openapidiff/core/utils/RefPointer.java b/core/src/main/java/org/openapitools/openapidiff/core/utils/RefPointer.java index ab5a5643a..7da55e06f 100644 --- a/core/src/main/java/org/openapitools/openapidiff/core/utils/RefPointer.java +++ b/core/src/main/java/org/openapitools/openapidiff/core/utils/RefPointer.java @@ -57,7 +57,10 @@ public String getRefName(String ref) { final String baseRef = getBaseRefForType(refType.getName()); if (!ref.startsWith(baseRef)) { - throw new IllegalArgumentException("Invalid ref: " + ref); + // If the ref doesn't point to something in #/components, + // we return it as-is. This avoids making an assumption + // that we can simplify refs without collisions. + return ref; } return ref.substring(baseRef.length()); } diff --git a/core/src/test/java/org/openapitools/openapidiff/core/RemoteRefsDiffTest.java b/core/src/test/java/org/openapitools/openapidiff/core/RemoteRefsDiffTest.java new file mode 100644 index 000000000..48350ef49 --- /dev/null +++ b/core/src/test/java/org/openapitools/openapidiff/core/RemoteRefsDiffTest.java @@ -0,0 +1,42 @@ +package org.openapitools.openapidiff.core; + +import static org.openapitools.openapidiff.core.TestUtils.assertOpenApiAreEquals; +import static org.openapitools.openapidiff.core.TestUtils.assertOpenApiChangedEndpoints; +import static org.openapitools.openapidiff.core.TestUtils.assertSpecChangedButCompatible; + +import org.junit.jupiter.api.Test; + +public class RemoteRefsDiffTest { + + private final String OPENAPI_NESTED_REFS = "remoteRefs/specUsingNestedRefs.yaml"; + private final String OPENAPI_NO_REFS = "remoteRefs/specUsingNoRefs.yaml"; + private final String OPENAPI_SIMPLE_REFS = "remoteRefs/specUsingSimpleRefs.yaml"; + private final String OPENAPI_ELEMENT_REFS = "remoteRefs/specUsingElementRefs.yaml"; + private final String OPENAPI_MODIFIED_REFS = "remoteRefs/specUsingModifiedRefs.yaml"; + + @Test + public void testDiffSpecIsSameAsItself() { + assertOpenApiAreEquals(OPENAPI_NESTED_REFS, OPENAPI_NESTED_REFS); + } + + @Test + public void testDiffRefsSameAsInline() { + assertOpenApiAreEquals(OPENAPI_NESTED_REFS, OPENAPI_NO_REFS); + } + + @Test + public void testDiffNestedRefsSameAsSimpleRefs() { + assertOpenApiAreEquals(OPENAPI_NESTED_REFS, OPENAPI_SIMPLE_REFS); + } + + @Test + public void testDiffNestedRefsSameAsElementRefs() { + assertOpenApiAreEquals(OPENAPI_NESTED_REFS, OPENAPI_ELEMENT_REFS); + } + + @Test + public void testDiffShowsChangesWhenRefContentChanges() { + assertOpenApiChangedEndpoints(OPENAPI_NESTED_REFS, OPENAPI_MODIFIED_REFS); + assertSpecChangedButCompatible(OPENAPI_NESTED_REFS, OPENAPI_MODIFIED_REFS); + } +} diff --git a/core/src/test/resources/remoteRefs/reusableSchemas/AllInOne.yaml b/core/src/test/resources/remoteRefs/reusableSchemas/AllInOne.yaml new file mode 100644 index 000000000..6dca607f5 --- /dev/null +++ b/core/src/test/resources/remoteRefs/reusableSchemas/AllInOne.yaml @@ -0,0 +1,14 @@ +Pet: + allOf: + - $ref: '#/BasePet' + - type: object + required: + - pet_type + properties: + pet_type: + type: string +BasePet: + type: object + properties: + pet_color: + type: string \ No newline at end of file diff --git a/core/src/test/resources/remoteRefs/reusableSchemas/BasePet.yaml b/core/src/test/resources/remoteRefs/reusableSchemas/BasePet.yaml new file mode 100644 index 000000000..503195ed8 --- /dev/null +++ b/core/src/test/resources/remoteRefs/reusableSchemas/BasePet.yaml @@ -0,0 +1,4 @@ +type: object +properties: + pet_color: + type: string \ No newline at end of file diff --git a/core/src/test/resources/remoteRefs/reusableSchemas/PetWithModifiedContent.yaml b/core/src/test/resources/remoteRefs/reusableSchemas/PetWithModifiedContent.yaml new file mode 100644 index 000000000..a297fcbc8 --- /dev/null +++ b/core/src/test/resources/remoteRefs/reusableSchemas/PetWithModifiedContent.yaml @@ -0,0 +1,10 @@ +type: object +required: + - pet_type +properties: + pet_color: + type: string + pet_type: + type: string + pet_age: + type: integer \ No newline at end of file diff --git a/core/src/test/resources/remoteRefs/reusableSchemas/PetWithNestedRef.yaml b/core/src/test/resources/remoteRefs/reusableSchemas/PetWithNestedRef.yaml new file mode 100644 index 000000000..d79e286cf --- /dev/null +++ b/core/src/test/resources/remoteRefs/reusableSchemas/PetWithNestedRef.yaml @@ -0,0 +1,8 @@ +allOf: + - $ref: './BasePet.yaml' + - type: object + required: + - pet_type + properties: + pet_type: + type: string \ No newline at end of file diff --git a/core/src/test/resources/remoteRefs/reusableSchemas/PetWithoutNestedRef.yaml b/core/src/test/resources/remoteRefs/reusableSchemas/PetWithoutNestedRef.yaml new file mode 100644 index 000000000..bd5600f73 --- /dev/null +++ b/core/src/test/resources/remoteRefs/reusableSchemas/PetWithoutNestedRef.yaml @@ -0,0 +1,8 @@ +type: object +required: + - pet_type +properties: + pet_color: + type: string + pet_type: + type: string \ No newline at end of file diff --git a/core/src/test/resources/remoteRefs/specUsingElementRefs.yaml b/core/src/test/resources/remoteRefs/specUsingElementRefs.yaml new file mode 100644 index 000000000..ca3d42512 --- /dev/null +++ b/core/src/test/resources/remoteRefs/specUsingElementRefs.yaml @@ -0,0 +1,113 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. You can find out more about + Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, + #swagger](http://swagger.io/irc/). For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +paths: + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + explode: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + properties: + pets: + type: array + items: + $ref: '#/components/schemas/Cat' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + Pet: + content: + application/json: + schema: + $ref: './reusableSchemas/AllInOne.yaml#/Pet' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Cat: + description: Cat class + allOf: + - $ref: './reusableSchemas/AllInOne.yaml#/Pet' + type: object + properties: + name: + type: string + Dog: + description: Dog class + allOf: + - $ref: './reusableSchemas/AllInOne.yaml#/Pet' + type: object + properties: + bark: + type: string diff --git a/core/src/test/resources/remoteRefs/specUsingModifiedRefs.yaml b/core/src/test/resources/remoteRefs/specUsingModifiedRefs.yaml new file mode 100644 index 000000000..610d3b2d2 --- /dev/null +++ b/core/src/test/resources/remoteRefs/specUsingModifiedRefs.yaml @@ -0,0 +1,113 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. You can find out more about + Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, + #swagger](http://swagger.io/irc/). For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +paths: + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + explode: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + properties: + pets: + type: array + items: + $ref: '#/components/schemas/Cat' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + Pet: + content: + application/json: + schema: + $ref: './reusableSchemas/PetWithModifiedContent.yaml' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Cat: + description: Cat class + allOf: + - $ref: './reusableSchemas/PetWithModifiedContent.yaml' + type: object + properties: + name: + type: string + Dog: + description: Dog class + allOf: + - $ref: './reusableSchemas/PetWithModifiedContent.yaml' + type: object + properties: + bark: + type: string diff --git a/core/src/test/resources/remoteRefs/specUsingNestedRefs.yaml b/core/src/test/resources/remoteRefs/specUsingNestedRefs.yaml new file mode 100644 index 000000000..8031cde27 --- /dev/null +++ b/core/src/test/resources/remoteRefs/specUsingNestedRefs.yaml @@ -0,0 +1,113 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. You can find out more about + Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, + #swagger](http://swagger.io/irc/). For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +paths: + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + explode: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + properties: + pets: + type: array + items: + $ref: '#/components/schemas/Cat' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + Pet: + content: + application/json: + schema: + $ref: './reusableSchemas/PetWithNestedRef.yaml' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Cat: + description: Cat class + allOf: + - $ref: './reusableSchemas/PetWithNestedRef.yaml' + type: object + properties: + name: + type: string + Dog: + description: Dog class + allOf: + - $ref: './reusableSchemas/PetWithNestedRef.yaml' + type: object + properties: + bark: + type: string diff --git a/core/src/test/resources/remoteRefs/specUsingNoRefs.yaml b/core/src/test/resources/remoteRefs/specUsingNoRefs.yaml new file mode 100644 index 000000000..6190b9a8c --- /dev/null +++ b/core/src/test/resources/remoteRefs/specUsingNoRefs.yaml @@ -0,0 +1,129 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. You can find out more about + Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, + #swagger](http://swagger.io/irc/). For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +paths: + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + explode: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + properties: + pets: + type: array + items: + $ref: '#/components/schemas/Cat' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + Pet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Pet: + type: object + required: + - pet_type + properties: + pet_type: + nullable: false + type: string + Cat: + description: Cat class + type: object + required: + - pet_type + properties: + pet_type: + type: string + name: + type: string + pet_color: + type: string + Dog: + description: Dog class + type: object + required: + - pet_type + properties: + pet_color: + type: string + pet_type: + type: string + bark: + type: string diff --git a/core/src/test/resources/remoteRefs/specUsingSimpleRefs.yaml b/core/src/test/resources/remoteRefs/specUsingSimpleRefs.yaml new file mode 100644 index 000000000..29a47100d --- /dev/null +++ b/core/src/test/resources/remoteRefs/specUsingSimpleRefs.yaml @@ -0,0 +1,113 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. You can find out more about + Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, + #swagger](http://swagger.io/irc/). For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +paths: + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + explode: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + properties: + pets: + type: array + items: + $ref: '#/components/schemas/Cat' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + Pet: + content: + application/json: + schema: + $ref: './reusableSchemas/PetWithoutNestedRef.yaml' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Cat: + description: Cat class + allOf: + - $ref: './reusableSchemas/PetWithoutNestedRef.yaml' + type: object + properties: + name: + type: string + Dog: + description: Dog class + allOf: + - $ref: './reusableSchemas/PetWithoutNestedRef.yaml' + type: object + properties: + bark: + type: string