diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..82a701f9a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# top-most EditorConfig file +root = true + +[*] +# (Please don't specify an indent_size here; that has too many unintended consequences.) +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +# JS/TS files +[*.{js,jsx,ts,tsx}] +indent_size = 2 + +# Json files +[*.{json}] +indent_size = 2 + +# Yaml files +[*.{yaml}] +indent_size = 2 diff --git a/common/changes/@autorest/codemodel/tests-backlog_2021-02-03-21-59.json b/common/changes/@autorest/codemodel/tests-backlog_2021-02-03-21-59.json new file mode 100644 index 000000000..e758bdc83 --- /dev/null +++ b/common/changes/@autorest/codemodel/tests-backlog_2021-02-03-21-59.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@autorest/codemodel", + "comment": "", + "type": "none" + } + ], + "packageName": "@autorest/codemodel", + "email": "tiguerin@microsoft.com" +} \ No newline at end of file diff --git a/common/changes/@autorest/core/tests-backlog_2021-02-03-20-50.json b/common/changes/@autorest/core/tests-backlog_2021-02-03-20-50.json new file mode 100644 index 000000000..4af27cfae --- /dev/null +++ b/common/changes/@autorest/core/tests-backlog_2021-02-03-20-50.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@autorest/core", + "comment": "Internal: Add some tests to the tree shaker", + "type": "patch" + } + ], + "packageName": "@autorest/core", + "email": "tiguerin@microsoft.com" +} \ No newline at end of file diff --git a/common/changes/@autorest/modelerfour/tests-backlog_2021-02-03-20-50.json b/common/changes/@autorest/modelerfour/tests-backlog_2021-02-03-20-50.json new file mode 100644 index 000000000..147f230cd --- /dev/null +++ b/common/changes/@autorest/modelerfour/tests-backlog_2021-02-03-20-50.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@autorest/modelerfour", + "comment": "Internal: Move out test custom matchers to seperate package", + "type": "patch" + } + ], + "packageName": "@autorest/modelerfour", + "email": "tiguerin@microsoft.com" +} \ No newline at end of file diff --git a/common/changes/@autorest/test-utils/tests-backlog_2021-02-03-20-50.json b/common/changes/@autorest/test-utils/tests-backlog_2021-02-03-20-50.json new file mode 100644 index 000000000..7570d1dd6 --- /dev/null +++ b/common/changes/@autorest/test-utils/tests-backlog_2021-02-03-20-50.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@autorest/test-utils", + "comment": "Initial content, include file snapshot matching", + "type": "minor" + } + ], + "packageName": "@autorest/test-utils", + "email": "tiguerin@microsoft.com" +} diff --git a/common/changes/@azure-tools/oai2-to-oai3/tests-backlog_2021-02-03-20-50.json b/common/changes/@azure-tools/oai2-to-oai3/tests-backlog_2021-02-03-20-50.json new file mode 100644 index 000000000..205b67e49 --- /dev/null +++ b/common/changes/@azure-tools/oai2-to-oai3/tests-backlog_2021-02-03-20-50.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@azure-tools/oai2-to-oai3", + "comment": "Internal: Add scenario tests", + "type": "patch" + } + ], + "packageName": "@azure-tools/oai2-to-oai3", + "email": "tiguerin@microsoft.com" +} \ No newline at end of file diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 0c88cce06..ba9cb7f4a 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -18,6 +18,7 @@ dependencies: '@rush-temp/modelerfour': 'file:projects/modelerfour.tgz' '@rush-temp/oai2-to-oai3': 'file:projects/oai2-to-oai3.tgz_prettier@2.2.1' '@rush-temp/schemas': 'file:projects/schemas.tgz' + '@rush-temp/test-utils': 'file:projects/test-utils.tgz_prettier@2.2.1' '@types/body-parser': 1.19.0 '@types/commonmark': 0.27.4 '@types/deep-equal': 1.0.1 @@ -506,7 +507,7 @@ packages: globals: 12.4.0 ignore: 4.0.6 import-fresh: 3.3.0 - js-yaml: 3.14.1 + js-yaml: 3.13.1 lodash: 4.17.20 minimatch: 3.0.4 strip-json-comments: 3.1.1 @@ -520,7 +521,7 @@ packages: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 - js-yaml: 3.14.1 + js-yaml: 3.13.1 resolve-from: 5.0.0 dev: false engines: @@ -1938,7 +1939,7 @@ packages: dependencies: caniuse-lite: 1.0.30001183 colorette: 1.2.1 - electron-to-chromium: 1.3.652 + electron-to-chromium: 1.3.653 escalade: 3.1.1 node-releases: 1.1.70 dev: false @@ -2817,10 +2818,10 @@ packages: dev: false resolution: integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - /electron-to-chromium/1.3.652: + /electron-to-chromium/1.3.653: dev: false resolution: - integrity: sha512-85J5D0Ksxjq2MIHfgwOURRej72UMlexbaa7t+oKTJan3Pa/RBE8vJ4/JzwaQjLCElPvd0XeLWi7+xYTVrq96aA== + integrity: sha512-LehOhcl74u9fkV9Un6WahJ+Xh+0FZLCCDnKYis1Olx1DX2ugRww5PJicE65OG8yznMj8EOQZRcz6FSV1xKxqsA== /emittery/0.7.2: dev: false engines: @@ -3202,7 +3203,7 @@ packages: import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.1 - js-yaml: 3.14.1 + js-yaml: 3.13.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash: 4.17.20 @@ -5133,14 +5134,6 @@ packages: hasBin: true resolution: integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - /js-yaml/3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - dev: false - hasBin: true - resolution: - integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== /js-yaml/4.0.0: dependencies: argparse: 2.0.1 @@ -9143,9 +9136,7 @@ packages: eslint: 7.19.0 eslint-plugin-prettier: 3.2.0_eslint@7.19.0+prettier@2.2.1 eslint-plugin-unicorn: 27.0.0_eslint@7.19.0 - expect: 26.6.2 jest: 26.6.3 - jest-snapshot: 26.6.2 prettier: 2.2.1 recursive-diff: 1.0.8 rimraf: 3.0.2 @@ -9158,7 +9149,7 @@ packages: dev: false name: '@rush-temp/modelerfour' resolution: - integrity: sha512-FoIOdQ7TjmcaXomZinNzvF1jw1epQvnyoPAreXotN1qShiqgfQcs49N+7bBoe122fQf8cacWSqapHNhER4K1wg== + integrity: sha512-dDoKlI+WbFmKIg98l3+7kzsLZtSr/ufVsEnu0ow0+0S/AbUpT4NKpXI2KgAKW4TznZOl6ZJezJAKs0IxcYgVOQ== tarball: 'file:projects/modelerfour.tgz' version: 0.0.0 'file:projects/oai2-to-oai3.tgz_prettier@2.2.1': @@ -9186,7 +9177,7 @@ packages: peerDependencies: prettier: '*' resolution: - integrity: sha512-c3miz7la4bG0FxuVgMmZNrNdoyFkH218u1UyDt2xBrDpp/jbtm8y0YL/IMvGrFso1Yf2z7JGUhTjev4XSFo8Yg== + integrity: sha512-y3ZMMf925okHkt10QtBjIQFNUz+G+UkihzURLLBdRrCehA/yKReMmpM5TKNPnrcg1rGFn2y/a/kAWmUZOQVTZw== tarball: 'file:projects/oai2-to-oai3.tgz' version: 0.0.0 'file:projects/schemas.tgz': @@ -9196,6 +9187,25 @@ packages: integrity: sha512-R4SNYE56Q0TOMYcT8gSTZIInxE9vVJH1k54SR8Ksvg8HNkzG+Pko1NIxb8zpWFB74VEmx3TDaruHnodgJjUrvQ== tarball: 'file:projects/schemas.tgz' version: 0.0.0 + 'file:projects/test-utils.tgz_prettier@2.2.1': + dependencies: + '@types/jest': 26.0.20 + eslint: 7.19.0 + eslint-plugin-prettier: 3.2.0_eslint@7.19.0+prettier@2.2.1 + eslint-plugin-unicorn: 27.0.0_eslint@7.19.0 + expect: 26.6.2 + jest: 26.6.3 + jest-snapshot: 26.6.2 + rimraf: 3.0.2 + dev: false + id: 'file:projects/test-utils.tgz' + name: '@rush-temp/test-utils' + peerDependencies: + prettier: '*' + resolution: + integrity: sha512-8nMXR/fQrY7cWzKlnWAWLNAPsCqTy218Yq76aUySEg/K65B+nGDBNIZewWlUh3Dy4q/xEwC+EN8tG9/SSwQ9EA== + tarball: 'file:projects/test-utils.tgz' + version: 0.0.0 specifiers: '@azure-tools/async-io': ~3.0.0 '@azure-tools/datastore': ~4.1.0 @@ -9216,6 +9226,7 @@ specifiers: '@rush-temp/modelerfour': 'file:./projects/modelerfour.tgz' '@rush-temp/oai2-to-oai3': 'file:./projects/oai2-to-oai3.tgz' '@rush-temp/schemas': 'file:./projects/schemas.tgz' + '@rush-temp/test-utils': 'file:./projects/test-utils.tgz' '@types/body-parser': ^1.19.0 '@types/commonmark': ^0.27.0 '@types/deep-equal': ^1.0.1 diff --git a/packages/extensions/core/jest.config.js b/packages/extensions/core/jest.config.js index 2f827dc43..84c134b0c 100644 --- a/packages/extensions/core/jest.config.js +++ b/packages/extensions/core/jest.config.js @@ -5,7 +5,7 @@ const defaultConfig = require("../../../jest.default.config"); const config = { ...defaultConfig, setupFilesAfterEnv: ["/test/setupJest.ts"], - testMatch: ["/test/**/*.test.ts"], + testMatch: ["/test/**/*.test.ts", "/src/**/*.test.ts"], globals: { "ts-jest": { tsconfig: "tsconfig.json", diff --git a/packages/extensions/core/src/lib/pipeline/pipeline.ts b/packages/extensions/core/src/lib/pipeline/pipeline.ts index a4b606401..12da2458c 100644 --- a/packages/extensions/core/src/lib/pipeline/pipeline.ts +++ b/packages/extensions/core/src/lib/pipeline/pipeline.ts @@ -48,7 +48,7 @@ import { createTransformerPlugin, createGraphTransformerPlugin, } from "./plugins/transformer"; -import { createTreeShakerPlugin } from "./plugins/tree-shaker"; +import { createTreeShakerPlugin } from "./plugins/tree-shaker/tree-shaker"; import { createApiVersionParameterHandlerPlugin } from "./plugins/version-param-handler"; import { createJsonToYamlPlugin, createYamlToJsonPlugin } from "./plugins/yaml-and-json"; import { createOpenApiSchemaValidatorPlugin, createSwaggerSchemaValidatorPlugin } from "./schema-validation"; diff --git a/packages/extensions/core/src/lib/pipeline/plugins/tree-shaker/tree-shaker.test.ts b/packages/extensions/core/src/lib/pipeline/plugins/tree-shaker/tree-shaker.test.ts new file mode 100644 index 000000000..4d59120e5 --- /dev/null +++ b/packages/extensions/core/src/lib/pipeline/plugins/tree-shaker/tree-shaker.test.ts @@ -0,0 +1,87 @@ +import { Source } from "@azure-tools/datastore"; +import { JsonType, Model } from "@azure-tools/openapi"; +import { create } from "domain"; +import { OAI3Shaker } from "./tree-shaker"; + +const createTestModel = (model: any): Model => { + return { + openApi: "3.0.0", + paths: {}, + info: { + title: "Test spec", + version: "1.0.0", + }, + servers: {}, + security: {}, + components: {}, + tags: {}, + ...model, + }; +}; + +const shake = async (model: any) => { + const source: Source = { + ReadObject: () => Promise.resolve(createTestModel(model)), + key: "test", + }; + const shaker = new OAI3Shaker(source, false); + return shaker.getOutput(); +}; + +describe("Tree shaker", () => { + describe("when using x-ms-client-name", () => { + it("keeps x-ms-client-name when used on a schema", async () => { + const result = await shake({ + components: { + schemas: { + Foo: { + "type": JsonType.Object, + "x-ms-client-name": "FooClient", + }, + }, + }, + }); + + expect(result.components.schemas.Foo["x-ms-client-name"]).toEqual("FooClient"); + }); + + it("keeps x-ms-client-name when used on a parameter", async () => { + const result = await shake({ + paths: { + "/mypath": { + get: { + parameters: [{ "in": "query", "name": "some-param", "x-ms-client-name": "SomeParamClient" }], + }, + }, + }, + }); + + const param = Object.values(result.components.parameters)[0]; + expect(param["x-ms-client-name"]).toEqual("SomeParamClient"); + }); + + it("it removes x-ms-client-name on shaked model when used on property with inline model definition", async () => { + const result = await shake({ + components: { + schemas: { + Foo: { + type: JsonType.Object, + properties: { + bar: { + "x-ms-client-name": "barClient", + "type": JsonType.Object, + "properties": { + name: { type: JsonType.String }, + }, + }, + }, + }, + }, + }, + }); + + expect(result.components.schemas.Foo.properties.bar["x-ms-client-name"]).toEqual("barClient"); + expect(result.components.schemas["Foo-bar"]["x-ms-client-name"]).toBeUndefined(); + }); + }); +}); diff --git a/packages/extensions/core/src/lib/pipeline/plugins/tree-shaker.ts b/packages/extensions/core/src/lib/pipeline/plugins/tree-shaker/tree-shaker.ts similarity index 99% rename from packages/extensions/core/src/lib/pipeline/plugins/tree-shaker.ts rename to packages/extensions/core/src/lib/pipeline/plugins/tree-shaker/tree-shaker.ts index 76ee4d681..b0d3c0572 100644 --- a/packages/extensions/core/src/lib/pipeline/plugins/tree-shaker.ts +++ b/packages/extensions/core/src/lib/pipeline/plugins/tree-shaker/tree-shaker.ts @@ -11,8 +11,8 @@ import { JsonPath, Source, } from "@azure-tools/datastore"; -import { ConfigurationView } from "../../configuration"; -import { PipelinePlugin } from "../common"; +import { ConfigurationView } from "../../../configuration"; +import { PipelinePlugin } from "../../common"; import { values, length } from "@azure-tools/linq"; import { createHash } from "crypto"; diff --git a/packages/extensions/core/test/shaker.test.ts b/packages/extensions/core/test/shaker.test.ts deleted file mode 100644 index c66941155..000000000 --- a/packages/extensions/core/test/shaker.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as aio from "@azure-tools/async-io"; -import * as datastore from "@azure-tools/datastore"; -import assert from "assert"; -import { OAI3Shaker } from "../src/lib/pipeline/plugins/tree-shaker"; - -try { - require("source-map-support").install(); -} catch { - /* unused */ -} - -const resources = `${__dirname}../../../test/resources/shaker`; - -describe("TestShaker", () => { - // todo: fix test - xit("Test Shaker", async () => { - const inputUri = "mem://input.yaml"; - const outputUri = "mem://output.yaml"; - - const input = await aio.readFile(`${resources}/input.yaml`); - const output = await aio.readFile(`${resources}/output.yaml`); - - const map = new Map([ - [inputUri, input], - [outputUri, output], - ]); - const mfs = new datastore.MemoryFileSystem(map); - - const cts: datastore.CancellationTokenSource = { - cancel() { - /* unused */ - }, - dispose() { - /* unused */ - }, - token: { isCancellationRequested: false, onCancellationRequested: null }, - }; - const ds = new datastore.DataStore(cts.token); - const scope = ds.GetReadThroughScope(mfs); - const inputDataHandle = await scope.Read(inputUri); - const outputDataHandle = await scope.Read(outputUri); - - assert(inputDataHandle != null); - assert(outputDataHandle != null); - - if (inputDataHandle && outputDataHandle) { - // if (inputDataHandle) { - const outputObject = await outputDataHandle.ReadObject(); - const shaker = new OAI3Shaker(inputDataHandle, false); - - // testing: dump out the converted file - // console.log(FastStringify(shaken)); - - assert.deepEqual(await shaker.getOutput(), outputObject, "Should be the same"); - } - }); -}); diff --git a/packages/extensions/modelerfour/package.json b/packages/extensions/modelerfour/package.json index 3e8316d66..18d6e1d0a 100644 --- a/packages/extensions/modelerfour/package.json +++ b/packages/extensions/modelerfour/package.json @@ -41,6 +41,7 @@ "devDependencies": { "@autorest/codemodel": "~4.14.3", "@autorest/extension-base": "~3.1.0", + "@autorest/test-utils": "~0.0.1", "@azure-tools/async-io": "~3.0.0", "@azure-tools/codegen": "~2.5.0", "@azure-tools/datastore": "~4.1.0", @@ -58,8 +59,6 @@ "eslint-plugin-prettier": "~3.2.0", "eslint-plugin-unicorn": "~27.0.0", "eslint": "^7.17.0", - "expect": "~26.6.2", - "jest-snapshot": "~26.6.2", "jest": "^26.6.3", "prettier": "~2.2.1", "recursive-diff": "~1.0.6", diff --git a/packages/extensions/modelerfour/test/setupJest.ts b/packages/extensions/modelerfour/test/setupJest.ts index 1dae400c8..d2d6e4eda 100644 --- a/packages/extensions/modelerfour/test/setupJest.ts +++ b/packages/extensions/modelerfour/test/setupJest.ts @@ -1 +1,2 @@ -import "./custom-matchers"; +// eslint-disable-next-line unicorn/filename-case +import "@autorest/test-utils/dist/matchers"; diff --git a/packages/libs/codemodel/package.json b/packages/libs/codemodel/package.json index 42fc7d857..1c95a5f2b 100644 --- a/packages/libs/codemodel/package.json +++ b/packages/libs/codemodel/package.json @@ -11,7 +11,7 @@ "build": "tsc -p .", "watch": "tsc -p . --watch", "lint:fix": "eslint ./src --fix --ext .ts", - "lint": "eslint ./src --ext .ts", + "lint": "eslint ./src --ext .ts --max-warnings=0", "prepare": "npm run build", "test": "echo codemodel: No Tests.", "test:ci": "echo codemodel: No Tests.", diff --git a/packages/libs/oai2-to-oai3/jest.config.js b/packages/libs/oai2-to-oai3/jest.config.js index 663e7ade0..8ebeb48ac 100644 --- a/packages/libs/oai2-to-oai3/jest.config.js +++ b/packages/libs/oai2-to-oai3/jest.config.js @@ -5,6 +5,7 @@ const defaultConfig = require("../../../jest.default.config"); const config = { ...defaultConfig, testMatch: ["/test/**/*.test.ts"], + setupFilesAfterEnv: ["/test/setup-jest.ts"], }; module.exports = config; diff --git a/packages/libs/oai2-to-oai3/package.json b/packages/libs/oai2-to-oai3/package.json index e75ed6876..94fc75e7b 100644 --- a/packages/libs/oai2-to-oai3/package.json +++ b/packages/libs/oai2-to-oai3/package.json @@ -36,6 +36,7 @@ "homepage": "https://github.com/Azure/perks/tree/master/oai2-to-oai3#readme", "readme": "https://github.com/Azure/perks/tree/master/oai2-to-oai3/readme.md", "devDependencies": { + "@autorest/test-utils": "~0.0.1", "@types/jest": "^26.0.20", "@types/js-yaml": "~4.0.0", "@types/node": "~14.14.20", diff --git a/packages/libs/oai2-to-oai3/src/converter.ts b/packages/libs/oai2-to-oai3/src/converter.ts index 0531210f8..516f85f00 100644 --- a/packages/libs/oai2-to-oai3/src/converter.ts +++ b/packages/libs/oai2-to-oai3/src/converter.ts @@ -678,12 +678,6 @@ export class Oai2ToOai3 { return { value: createGraphProxy(this.originalFilename, pointer, this.mappings), pointer }; } - visitUnspecified(nodes: Iterable) { - for (const { value, pointer } of nodes) { - console.error(`?? Unknown item: ${pointer} : ${value}`); - } - } - async visitPaths(target: any, paths: Iterable, globalConsumes: Array, globalProduces: Array) { for (const { key: uri, pointer, children: pathItemMembers } of paths) { await this.visitPath(target, uri, pointer, pathItemMembers, globalConsumes, globalProduces); @@ -817,38 +811,22 @@ export class Oai2ToOai3 { } const parameterName = parsedRef.componentName; if (parsedRef.basePath === "/parameters/") { - // TODO: I think we don't need this at all and can just call the else. TO check when adding the unit tests. - if (parsedRef.file == "" || parsedRef.file === this.originalFilename) { - const dereferencedParameter = get(this.original, parsedRef.path); + const dereferencedParameter = await this.resolveReference(parsedRef.file, parsedRef.path); + if (!dereferencedParameter) { + throw new Error(`Cannot find reference ${value.$ref}`); + } - if ( - dereferencedParameter.in === "body" || - dereferencedParameter.type === "file" || - dereferencedParameter.in === "formData" - ) { - childIterator = () => visit(dereferencedParameter, [parameterName]); - value = dereferencedParameter; - pointer = parsedRef.path; - } - } else { - const dereferencedParameter = await this.resolveReference(parsedRef.file, parsedRef.path); - if (!dereferencedParameter) { - throw new Error(`Cannot find reference ${value.$ref}`); - } - - if ( - dereferencedParameter.in === "body" || - dereferencedParameter.type === "file" || - dereferencedParameter.in === "formData" - ) { - childIterator = () => visit(dereferencedParameter, [parameterName]); - value = dereferencedParameter; - pointer = parsedRef.path; - } + if ( + dereferencedParameter.in === "body" || + dereferencedParameter.type === "file" || + dereferencedParameter.in === "formData" + ) { + childIterator = () => visit(dereferencedParameter, [parameterName]); + value = dereferencedParameter; + pointer = parsedRef.path; } } else { - // TODO: Throw exception - console.error("### CAN'T RESOLVE $ref", value.$ref); + throw new Error(`Reference ${value.$ref} is invalid. It should be referencing a parameter(#/parameters/xzy)`); } } diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-body-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-body-refs/other.json new file mode 100644 index 000000000..b04af02a7 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-body-refs/other.json @@ -0,0 +1,15 @@ +{ + "servers": [], + "components": { + "schemas": { + "MyBodySchema": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-body-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-body-refs/swagger.json new file mode 100644 index 000000000..53e9b7e5f --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-body-refs/swagger.json @@ -0,0 +1,39 @@ +{ + "servers": [], + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "openapi": "3.0.0", + "info": { + "x-ms-metadata": { + "apiVersions": [ + "test-0.1" + ] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "paths": { + "/test": { + "get": { + "operationId": "test", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MyBodySchema" + } + } + }, + "required": true, + "x-ms-requestBody-name": "MyBodyParam" + }, + "x-ms-requestBody-index": 0, + "responses": { + "200": { + "description": "OK." + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameterized-host-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameterized-host-refs/other.json new file mode 100644 index 000000000..2f02a4f59 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameterized-host-refs/other.json @@ -0,0 +1,19 @@ +{ + "servers": [], + "components": { + "parameters": { + "GlobalEndpoint": { + "name": "Endpoint", + "in": "path", + "description": "Shared endpoint param.", + "required": true, + "x-ms-parameter-location": "client", + "x-ms-skip-url-encoding": true, + "schema": { + "default": "https://api.cognitive.microsoft.com", + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameterized-host-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameterized-host-refs/swagger.json new file mode 100644 index 000000000..c062463e2 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameterized-host-refs/swagger.json @@ -0,0 +1,35 @@ +{ + "servers": [ + { + "url": "{Endpoint}", + "variables": { + "Endpoint": { + "x-name": "Endpoint", + "description": "Shared endpoint param.", + "x-ms-parameter-location": "client", + "x-required": true, + "x-type": "string", + "x-in": "path", + "x-ms-skip-url-encoding": true, + "default": "https://api.cognitive.microsoft.com", + "x-ms-original": { + "$ref": "other.json#/components/parameters/GlobalEndpoint" + } + } + } + } + ], + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "openapi": "3.0.0", + "info": { + "x-ms-metadata": { + "apiVersions": [ + "test-0.1" + ] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "paths": {} +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameters-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameters-refs/other.json new file mode 100644 index 000000000..d16b26ddd --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameters-refs/other.json @@ -0,0 +1,35 @@ +{ + "servers": [], + "components": { + "parameters": { + "QueryParm": { + "name": "MyQueryParam", + "in": "query", + "required": true, + "schema": { + "items": { + "$ref": "#/components/schemas/MyQuerySchema" + } + } + }, + "HeaderParam": { + "name": "MyHeaderParam", + "in": "query", + "required": true, + "schema": { + "items": { + "$ref": "#/components/schemas/MyHeaderSchema" + } + } + } + }, + "schemas": { + "MyQuerySchema": { + "type": "string" + }, + "MyHeaderSchema": { + "type": "string" + } + } + } +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameters-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameters-refs/swagger.json new file mode 100644 index 000000000..0b02ac0f6 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-parameters-refs/swagger.json @@ -0,0 +1,35 @@ +{ + "servers": [], + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "openapi": "3.0.0", + "info": { + "x-ms-metadata": { + "apiVersions": [ + "test-0.1" + ] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "paths": { + "/test": { + "get": { + "operationId": "test", + "parameters": [ + { + "$ref": "other.json#/components/parameters/QueryParm" + }, + { + "$ref": "other.json#/components/parameters/HeaderParam" + } + ], + "responses": { + "200": { + "description": "OK." + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-schema-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-schema-refs/other.json new file mode 100644 index 000000000..63b0cca3e --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-schema-refs/other.json @@ -0,0 +1,15 @@ +{ + "servers": [], + "components": { + "schemas": { + "MySharedSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-schema-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-schema-refs/swagger.json new file mode 100644 index 000000000..083eb363e --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/expected/cross-file-schema-refs/swagger.json @@ -0,0 +1,28 @@ +{ + "servers": [], + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "openapi": "3.0.0", + "info": { + "x-ms-metadata": { + "apiVersions": [ + "test-0.1" + ] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "paths": {}, + "components": { + "schemas": { + "MySchema": { + "type": "object", + "properties": { + "myProp": { + "$ref": "other.json#/components/schemas/MySharedSchema" + } + } + } + } + } +} \ No newline at end of file diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-body-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-body-refs/other.json new file mode 100644 index 000000000..86c1000a8 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-body-refs/other.json @@ -0,0 +1,22 @@ +{ + "parameters": { + "BodyParam": { + "in": "body", + "name": "MyBodyParam", + "required": true, + "schema": { + "$ref": "#/definitions/MyBodySchema" + } + } + }, + "definitions": { + "MyBodySchema": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + } + } +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-body-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-body-refs/swagger.json new file mode 100644 index 000000000..0cd65018e --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-body-refs/swagger.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "swagger": "2.0", + "info": { + "x-ms-metadata": { + "apiVersions": ["test-0.1"] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "paths": { + "/test": { + "get": { + "operationId": "test", + "parameters": [{ "$ref": "other.json#/parameters/BodyParam" }], + "responses": { + "200": { + "description": "OK." + } + } + } + } + }, + "definitions": {} +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameterized-host-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameterized-host-refs/other.json new file mode 100644 index 000000000..56f2eb03f --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameterized-host-refs/other.json @@ -0,0 +1,14 @@ +{ + "parameters": { + "GlobalEndpoint": { + "name": "Endpoint", + "description": "Shared endpoint param.", + "x-ms-parameter-location": "client", + "required": true, + "type": "string", + "in": "path", + "x-ms-skip-url-encoding": true, + "default": "https://api.cognitive.microsoft.com" + } + } +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameterized-host-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameterized-host-refs/swagger.json new file mode 100644 index 000000000..db6ea2dc9 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameterized-host-refs/swagger.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "swagger": "2.0", + "info": { + "x-ms-metadata": { + "apiVersions": ["test-0.1"] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "x-ms-parameterized-host": { + "hostTemplate": "{Endpoint}", + "useSchemePrefix": false, + "parameters": [ + { + "$ref": "other.json#/parameters/GlobalEndpoint" + } + ] + }, + "paths": {}, + "definitions": {} +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameters-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameters-refs/other.json new file mode 100644 index 000000000..80a90d732 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameters-refs/other.json @@ -0,0 +1,28 @@ +{ + "parameters": { + "QueryParm": { + "in": "query", + "name": "MyQueryParam", + "required": true, + "schema": { + "$ref": "#/definitions/MyQuerySchema" + } + }, + "HeaderParam": { + "in": "query", + "name": "MyHeaderParam", + "required": true, + "schema": { + "$ref": "#/definitions/MyHeaderSchema" + } + } + }, + "definitions": { + "MyQuerySchema": { + "type": "string" + }, + "MyHeaderSchema": { + "type": "string" + } + } +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameters-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameters-refs/swagger.json new file mode 100644 index 000000000..38ab6a98b --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-parameters-refs/swagger.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "swagger": "2.0", + "info": { + "x-ms-metadata": { + "apiVersions": ["test-0.1"] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "paths": { + "/test": { + "get": { + "operationId": "test", + "parameters": [ + { "$ref": "other.json#/parameters/QueryParm" }, + { "$ref": "other.json#/parameters/HeaderParam" } + ], + "responses": { + "200": { + "description": "OK." + } + } + } + } + }, + "definitions": {} +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-schema-refs/other.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-schema-refs/other.json new file mode 100644 index 000000000..e2496c74b --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-schema-refs/other.json @@ -0,0 +1,12 @@ +{ + "definitions": { + "MySharedSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + } +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-schema-refs/swagger.json b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-schema-refs/swagger.json new file mode 100644 index 000000000..b0c17f4ba --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/inputs/cross-file-schema-refs/swagger.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json", + "swagger": "2.0", + "info": { + "x-ms-metadata": { + "apiVersions": ["test-0.1"] + }, + "title": "Test", + "description": "test", + "version": "test-0.1" + }, + "paths": {}, + "definitions": { + "MySchema": { + "type": "object", + "properties": { + "myProp": { "$ref": "other.json#/definitions/MySharedSchema" } + } + } + } +} diff --git a/packages/libs/oai2-to-oai3/test/scenarios/scenarios.test.ts b/packages/libs/oai2-to-oai3/test/scenarios/scenarios.test.ts new file mode 100644 index 000000000..77f30ff61 --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/scenarios/scenarios.test.ts @@ -0,0 +1,52 @@ +import fs from "fs"; +import { basename, join } from "path"; +import { convertOai2ToOai3, OaiToOai3FileInput } from "../../src"; + +const inputsFolder = `${__dirname}/inputs/`; +const expectedFolder = `${__dirname}/expected/`; + +const getOAI3InputsFromTestFiles = async ( + testName: string, + filenames: string[], +): Promise> => { + const map = new Map(); + for (const filename of filenames) { + const buffer = await fs.promises.readFile(join(inputsFolder, testName, filename)); + + const name = basename(filename); + map.set(name, { name, schema: JSON.parse(buffer.toString()) }); + } + return map; +}; + +const expectInputsMatchSnapshots = async (testName: string, filenames: string[]) => { + const map = await getOAI3InputsFromTestFiles(testName, filenames); + + const results = await convertOai2ToOai3(map); + for (const result of results) { + const jsonResult = JSON.stringify(result.result, null, 2); + expect(jsonResult).toMatchRawFileSnapshot(join(expectedFolder, testName, result.name)); + } +}; + +describe("Scenario testings", () => { + it("Convert cross file schema references", async () => { + // The expected result is for the body parameter to be copied over but not the schema. + await expectInputsMatchSnapshots("cross-file-schema-refs", ["swagger.json", "other.json"]); + }); + + it("Convert cross file regular parameters", async () => { + // The expected result is the ref just change from /parameters -> /components/parameters. + await expectInputsMatchSnapshots("cross-file-parameters-refs", ["swagger.json", "other.json"]); + }); + + it("Convert cross file body parameter", async () => { + // The expected result is the ref just change from /defnitions -> /components/schemas. + await expectInputsMatchSnapshots("cross-file-body-refs", ["swagger.json", "other.json"]); + }); + + it("Convert cross file parameterized host", async () => { + // The expected result is the parmaeter to be included/expanded in the OpenAPI3 server property. + await expectInputsMatchSnapshots("cross-file-parameterized-host-refs", ["swagger.json", "other.json"]); + }); +}); diff --git a/packages/libs/oai2-to-oai3/test/setup-jest.ts b/packages/libs/oai2-to-oai3/test/setup-jest.ts new file mode 100644 index 000000000..68f3becef --- /dev/null +++ b/packages/libs/oai2-to-oai3/test/setup-jest.ts @@ -0,0 +1 @@ +import "@autorest/test-utils/dist/matchers"; diff --git a/packages/testing/test-utils/.eslintrc.yaml b/packages/testing/test-utils/.eslintrc.yaml new file mode 100644 index 000000000..a4b1e3532 --- /dev/null +++ b/packages/testing/test-utils/.eslintrc.yaml @@ -0,0 +1,3 @@ +parser: "@typescript-eslint/parser" +extends: + - "../../../.default-eslintrc.yaml" \ No newline at end of file diff --git a/packages/testing/test-utils/package.json b/packages/testing/test-utils/package.json new file mode 100644 index 000000000..fe3418be3 --- /dev/null +++ b/packages/testing/test-utils/package.json @@ -0,0 +1,44 @@ +{ + "name": "@autorest/test-utils", + "version": "0.0.1", + "description": "Set of testing utils that are used across packages", + "main": "./dist/index.js", + "typings": "./dist/index.d.ts", + "scripts": { + "build": "tsc -p .", + "watch": "tsc -p . --watch", + "clean": "rimraf ./dist", + "lint:fix": "eslint ./src --fix --ext .ts", + "lint": "eslint ./src --ext .ts --max-warnings=0", + "test:ci": "echo 'No tests'", + "test": "echo 'No tests'" + }, + "engines": { + "node": ">=10.13.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Azure/autorest.git" + }, + "keywords": [ + "autorest" + ], + "author": "Microsoft Corporation", + "license": "MIT", + "bugs": { + "url": "https://github.com/Azure/autorest/issues" + }, + "homepage": "https://github.com/Azure/autorest#readme", + "dependencies": { + "expect": "~26.6.2", + "jest-snapshot": "~26.6.2", + "jest": "^26.6.3" + }, + "devDependencies": { + "@types/jest": "^26.0.20", + "eslint-plugin-prettier": "~3.2.0", + "eslint-plugin-unicorn": "~27.0.0", + "eslint": "^7.17.0", + "rimraf": "^3.0.2" + } +} diff --git a/packages/testing/test-utils/readme.md b/packages/testing/test-utils/readme.md new file mode 100644 index 000000000..629b458c8 --- /dev/null +++ b/packages/testing/test-utils/readme.md @@ -0,0 +1,3 @@ +# Autorest Testing + +This package contains a set of utilities used for testing such as custom matchers. diff --git a/packages/testing/test-utils/src/index.ts b/packages/testing/test-utils/src/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/extensions/modelerfour/test/custom-matchers.ts b/packages/testing/test-utils/src/matchers/file-snapshot.ts similarity index 92% rename from packages/extensions/modelerfour/test/custom-matchers.ts rename to packages/testing/test-utils/src/matchers/file-snapshot.ts index 24f35a22c..d260e9ad4 100644 --- a/packages/extensions/modelerfour/test/custom-matchers.ts +++ b/packages/testing/test-utils/src/matchers/file-snapshot.ts @@ -6,7 +6,7 @@ import * as path from "path"; declare global { namespace jest { interface Matchers { - toMatchRawFileSnapshot(snapshotFile: string): CustomMatcherResult; + toMatchRawFileSnapshot(snapshotFile: string): jest.CustomMatcherResult; } } } @@ -39,7 +39,10 @@ function toMatchRawFileSnapshot( }; } - const filepath = getAbsolutePathToSnapshot(this.testPath!, filename); + if (!this.testPath) { + throw new Error("Unexpected matcher state, testPath is undefined"); + } + const filepath = getAbsolutePathToSnapshot(this.testPath, filename); const content: string = received; const updateSnapshot: "none" | "all" | "new" = (this.snapshotState as any)._updateSnapshot; diff --git a/packages/testing/test-utils/src/matchers/index.ts b/packages/testing/test-utils/src/matchers/index.ts new file mode 100644 index 000000000..10eef8a0e --- /dev/null +++ b/packages/testing/test-utils/src/matchers/index.ts @@ -0,0 +1,3 @@ +// Import the all custom matchers +// This is to be used inside a jest setup step. +import "./file-snapshot"; diff --git a/packages/testing/test-utils/tsconfig.json b/packages/testing/test-utils/tsconfig.json new file mode 100644 index 000000000..1e0ae4ad8 --- /dev/null +++ b/packages/testing/test-utils/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/rush.json b/rush.json index 3fb3a34d9..6ce013ae7 100644 --- a/rush.json +++ b/rush.json @@ -60,6 +60,12 @@ "reviewCategory": "production", "shouldPublish": true }, + { + "packageName": "@autorest/test-utils", + "projectFolder": "packages/testing/test-utils", + "reviewCategory": "production", + "shouldPublish": true + }, { "packageName": "@autorest/extension-base", "projectFolder": "packages/libs/extension-base",