diff --git a/package-lock.json b/package-lock.json index 86405d68..eb1d84ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@ts-common/source-map": "0.5.0", "@ts-common/string-map": "0.3.0", "autorest": "^3.8.0", + "fast-deep-equal": "^3.1.3", "js-yaml": "^4.1.0", "json-pointer": "0.6.2", "json-refs": "^3.0.15", @@ -3345,7 +3346,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-json-stable-stringify": { diff --git a/package.json b/package.json index 4dcc010a..2d185baa 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@ts-common/source-map": "0.5.0", "@ts-common/string-map": "0.3.0", "autorest": "^3.8.0", + "fast-deep-equal": "^3.1.3", "js-yaml": "^4.1.0", "json-pointer": "0.6.2", "json-refs": "^3.0.15", diff --git a/src/lib/util/resolveSwagger.ts b/src/lib/util/resolveSwagger.ts index adac48f7..45bbfa6a 100644 --- a/src/lib/util/resolveSwagger.ts +++ b/src/lib/util/resolveSwagger.ts @@ -6,6 +6,7 @@ import { toArray } from "@ts-common/iterator" import { cloneDeep, Data, FilePosition, getFilePosition, getInfo, getPath, ObjectInfo } from "@ts-common/source-map" import * as sourceMap from "source-map" import * as sm from "@ts-common/string-map" +import equal from "fast-deep-equal" import { readFileSync, writeFileSync } from "fs" import * as path from "path" import { pathToJsonPointer } from "./utils" @@ -247,7 +248,7 @@ export class ResolveSwagger { if (allOfSchema.properties) { sm.keys(allOfSchema.properties).forEach(key => { if (sm.keys(schemaList).some(k => k === key)) { - if (!this.isEqual(allOfSchema.properties[key], schemaList[key])) { + if (!this.isEqual(allOfSchema.properties[key], schemaList[key]) && !equal(allOfSchema.properties[key], schemaList[key])) { const allOfProp = allOfSchema.properties[key] const allOfPath = getPath(getInfo(allOfProp) as ObjectInfo) const allOfOriginalPosition = this.map.originalPositionFor(getFilePosition(allOfProp) as FilePosition) diff --git a/src/test/incompatiblePropertiesTest.ts b/src/test/incompatiblePropertiesTest.ts index 7cf13e32..dc2e16aa 100644 --- a/src/test/incompatiblePropertiesTest.ts +++ b/src/test/incompatiblePropertiesTest.ts @@ -3,6 +3,14 @@ import * as path from "path" import { OpenApiDiff } from ".." import { fileUrl } from "./fileUrl" +test.each(["different-names", "duplicate-names", "reference-equals", "structural-equals"])("should pass for %s", async testName => { + const diff = new OpenApiDiff({}) + const file = `src/test/specs/incompatible-properties/${testName}.json` + + // expected to pass + await diff.compare(file, file) +}) + // This test is part of regression test suite for https://github.com/Azure/azure-sdk-tools/issues/5981 // Given a property with given type and name // When another property with the same name but an incompatible type is referenced diff --git a/src/test/specs/incompatible-properties/common-types.json b/src/test/specs/incompatible-properties/common-types.json new file mode 100644 index 00000000..dc7b6474 --- /dev/null +++ b/src/test/specs/incompatible-properties/common-types.json @@ -0,0 +1,18 @@ +{ + "swagger": "2.0", + "info": { + "title": "common-types", + "version": "1.0" + }, + "paths": {}, + "definitions": { + "Foo": { + "type": "object", + "properties": { + "p1": { + "type": "string" + } + } + } + } +} diff --git a/src/test/specs/incompatible-properties/different-names.json b/src/test/specs/incompatible-properties/different-names.json new file mode 100644 index 00000000..5f4e7b86 --- /dev/null +++ b/src/test/specs/incompatible-properties/different-names.json @@ -0,0 +1,31 @@ +{ + "swagger": "2.0", + "info": { + "title": "different-names", + "version": "1.0" + }, + "paths": {}, + "definitions": { + "Bar": { + "type": "object", + "properties": { + "p1": { + "type": "string" + } + }, + "allOf": [ + { + "$ref": "./common-types.json#/definitions/Foo" + } + ] + }, + "Baz": { + "type": "object", + "properties": { + "p1": { + "type": "object" + } + } + } + } +} diff --git a/src/test/specs/incompatible-properties/duplicate-names.json b/src/test/specs/incompatible-properties/duplicate-names.json new file mode 100644 index 00000000..1cba0803 --- /dev/null +++ b/src/test/specs/incompatible-properties/duplicate-names.json @@ -0,0 +1,31 @@ +{ + "swagger": "2.0", + "info": { + "title": "duplicate-names", + "version": "1.0" + }, + "paths": {}, + "definitions": { + "Bar": { + "type": "object", + "properties": { + "p1": { + "type": "string" + } + }, + "allOf": [ + { + "$ref": "./common-types.json#/definitions/Foo" + } + ] + }, + "Foo": { + "type": "object", + "properties": { + "p1": { + "type": "object" + } + } + } + } +} diff --git a/src/test/specs/incompatible-properties/reference-equals.json b/src/test/specs/incompatible-properties/reference-equals.json new file mode 100644 index 00000000..b3b77ea9 --- /dev/null +++ b/src/test/specs/incompatible-properties/reference-equals.json @@ -0,0 +1,37 @@ +{ + "swagger": "2.0", + "info": { + "title": "structural-equality", + "version": "1.0" + }, + "paths": {}, + "definitions": { + "Foo": { + "type": "object", + "properties": { + "bar": { + "$ref": "#/definitions/MyObject" + } + }, + "allOf": [ + { + "$ref": "#/definitions/Foo2" + } + ] + }, + "Foo2": { + "type": "object", + "properties": { + "bar": { + "$ref": "#/definitions/MyObject" + } + } + }, + "MyObject": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } +} diff --git a/src/test/specs/incompatible-properties/structural-equals.json b/src/test/specs/incompatible-properties/structural-equals.json new file mode 100644 index 00000000..641f80c9 --- /dev/null +++ b/src/test/specs/incompatible-properties/structural-equals.json @@ -0,0 +1,37 @@ +{ + "swagger": "2.0", + "info": { + "title": "structural-equality", + "version": "1.0" + }, + "paths": {}, + "definitions": { + "Foo": { + "type": "object", + "properties": { + "bar": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "allOf": [ + { + "$ref": "#/definitions/Foo2" + } + ] + }, + "Foo2": { + "type": "object", + "properties": { + "bar": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } +}