From 8ee40ccbe963a0a5e3e998c1652378e1035dc40d Mon Sep 17 00:00:00 2001
From: vsrs <vit@conrlab.com>
Date: Wed, 20 May 2020 21:03:49 +0300
Subject: vscode client side tests

---
 editors/code/.vscodeignore                    |   2 +-
 editors/code/package-lock.json                | 768 ++++++++++++++++++++++++++
 editors/code/package.json                     |  15 +-
 editors/code/rollup.config.js                 |   4 +-
 editors/code/src/cargo.ts                     |  63 ++-
 editors/code/tests/runTests.ts                |  46 ++
 editors/code/tests/unit/index.ts              |  38 ++
 editors/code/tests/unit/launch_config.test.ts |  52 ++
 editors/code/tsconfig.json                    |   9 +-
 9 files changed, 965 insertions(+), 32 deletions(-)
 create mode 100644 editors/code/tests/runTests.ts
 create mode 100644 editors/code/tests/unit/index.ts
 create mode 100644 editors/code/tests/unit/launch_config.test.ts

(limited to 'editors/code')

diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore
index 257b744bf..7149ab799 100644
--- a/editors/code/.vscodeignore
+++ b/editors/code/.vscodeignore
@@ -1,5 +1,5 @@
 **
-!out/main.js
+!out/src/main.js
 !package.json
 !package-lock.json
 !ra_syntax_tree.tmGrammar.json
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 06178990f..c322b02c8 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -81,12 +81,41 @@
             "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
             "dev": true
         },
+        "@types/events": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
+            "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
+            "dev": true
+        },
+        "@types/glob": {
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
+            "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
+            "dev": true,
+            "requires": {
+                "@types/events": "*",
+                "@types/minimatch": "*",
+                "@types/node": "*"
+            }
+        },
         "@types/json-schema": {
             "version": "7.0.4",
             "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
             "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
             "dev": true
         },
+        "@types/minimatch": {
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+            "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+            "dev": true
+        },
+        "@types/mocha": {
+            "version": "7.0.2",
+            "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",
+            "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==",
+            "dev": true
+        },
         "@types/node": {
             "version": "12.12.39",
             "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.39.tgz",
@@ -200,6 +229,15 @@
             "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
             "dev": true
         },
+        "agent-base": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+            "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+            "dev": true,
+            "requires": {
+                "es6-promisify": "^5.0.0"
+            }
+        },
         "ajv": {
             "version": "6.12.0",
             "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
@@ -212,6 +250,12 @@
                 "uri-js": "^4.2.2"
             }
         },
+        "ansi-colors": {
+            "version": "3.2.3",
+            "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
+            "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
+            "dev": true
+        },
         "ansi-escapes": {
             "version": "4.3.1",
             "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
@@ -244,6 +288,16 @@
                 "color-convert": "^1.9.0"
             }
         },
+        "anymatch": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+            "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+            "dev": true,
+            "requires": {
+                "normalize-path": "^3.0.0",
+                "picomatch": "^2.0.4"
+            }
+        },
         "argparse": {
             "version": "1.0.10",
             "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -283,6 +337,12 @@
             "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
             "dev": true
         },
+        "binary-extensions": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
+            "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
+            "dev": true
+        },
         "boolbase": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -308,6 +368,12 @@
                 "fill-range": "^7.0.1"
             }
         },
+        "browser-stdout": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
+            "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
+            "dev": true
+        },
         "buffer-crc32": {
             "version": "0.2.13",
             "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
@@ -326,6 +392,12 @@
             "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
             "dev": true
         },
+        "camelcase": {
+            "version": "5.3.1",
+            "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+            "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+            "dev": true
+        },
         "chalk": {
             "version": "2.4.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@@ -357,6 +429,22 @@
                 "parse5": "^3.0.1"
             }
         },
+        "chokidar": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz",
+            "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
+            "dev": true,
+            "requires": {
+                "anymatch": "~3.1.1",
+                "braces": "~3.0.2",
+                "fsevents": "~2.1.1",
+                "glob-parent": "~5.1.0",
+                "is-binary-path": "~2.1.0",
+                "is-glob": "~4.0.1",
+                "normalize-path": "~3.0.0",
+                "readdirp": "~3.2.0"
+            }
+        },
         "cli-cursor": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -372,6 +460,42 @@
             "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
             "dev": true
         },
+        "cliui": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
+            "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+            "dev": true,
+            "requires": {
+                "string-width": "^3.1.0",
+                "strip-ansi": "^5.2.0",
+                "wrap-ansi": "^5.1.0"
+            },
+            "dependencies": {
+                "emoji-regex": {
+                    "version": "7.0.3",
+                    "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+                    "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+                    "dev": true
+                },
+                "is-fullwidth-code-point": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+                    "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+                    "dev": true
+                },
+                "string-width": {
+                    "version": "3.1.0",
+                    "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+                    "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                    "dev": true,
+                    "requires": {
+                        "emoji-regex": "^7.0.1",
+                        "is-fullwidth-code-point": "^2.0.0",
+                        "strip-ansi": "^5.1.0"
+                    }
+                }
+            }
+        },
         "color-convert": {
             "version": "1.9.3",
             "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -468,12 +592,27 @@
                 "ms": "^2.1.1"
             }
         },
+        "decamelize": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+            "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+            "dev": true
+        },
         "deep-is": {
             "version": "0.1.3",
             "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
             "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
             "dev": true
         },
+        "define-properties": {
+            "version": "1.1.3",
+            "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+            "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+            "dev": true,
+            "requires": {
+                "object-keys": "^1.0.12"
+            }
+        },
         "delayed-stream": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -486,6 +625,12 @@
             "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=",
             "dev": true
         },
+        "diff": {
+            "version": "3.5.0",
+            "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+            "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+            "dev": true
+        },
         "doctrine": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -562,6 +707,51 @@
             "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
             "dev": true
         },
+        "es-abstract": {
+            "version": "1.17.5",
+            "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
+            "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
+            "dev": true,
+            "requires": {
+                "es-to-primitive": "^1.2.1",
+                "function-bind": "^1.1.1",
+                "has": "^1.0.3",
+                "has-symbols": "^1.0.1",
+                "is-callable": "^1.1.5",
+                "is-regex": "^1.0.5",
+                "object-inspect": "^1.7.0",
+                "object-keys": "^1.1.1",
+                "object.assign": "^4.1.0",
+                "string.prototype.trimleft": "^2.1.1",
+                "string.prototype.trimright": "^2.1.1"
+            }
+        },
+        "es-to-primitive": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+            "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+            "dev": true,
+            "requires": {
+                "is-callable": "^1.1.4",
+                "is-date-object": "^1.0.1",
+                "is-symbol": "^1.0.2"
+            }
+        },
+        "es6-promise": {
+            "version": "4.2.8",
+            "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+            "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+            "dev": true
+        },
+        "es6-promisify": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+            "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+            "dev": true,
+            "requires": {
+                "es6-promise": "^4.0.3"
+            }
+        },
         "escape-string-regexp": {
             "version": "1.0.5",
             "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -764,6 +954,24 @@
                 "to-regex-range": "^5.0.1"
             }
         },
+        "find-up": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+            "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+            "dev": true,
+            "requires": {
+                "locate-path": "^3.0.0"
+            }
+        },
+        "flat": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz",
+            "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==",
+            "dev": true,
+            "requires": {
+                "is-buffer": "~2.0.3"
+            }
+        },
         "flat-cache": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
@@ -805,12 +1013,24 @@
             "dev": true,
             "optional": true
         },
+        "function-bind": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+            "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+            "dev": true
+        },
         "functional-red-black-tree": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
             "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
             "dev": true
         },
+        "get-caller-file": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+            "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+            "dev": true
+        },
         "glob": {
             "version": "7.1.6",
             "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
@@ -843,12 +1063,39 @@
                 "type-fest": "^0.8.1"
             }
         },
+        "growl": {
+            "version": "1.10.5",
+            "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
+            "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
+            "dev": true
+        },
+        "has": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+            "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+            "dev": true,
+            "requires": {
+                "function-bind": "^1.1.1"
+            }
+        },
         "has-flag": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
             "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
             "dev": true
         },
+        "has-symbols": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+            "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+            "dev": true
+        },
+        "he": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+            "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+            "dev": true
+        },
         "htmlparser2": {
             "version": "3.10.1",
             "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
@@ -863,6 +1110,54 @@
                 "readable-stream": "^3.1.1"
             }
         },
+        "http-proxy-agent": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
+            "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+            "dev": true,
+            "requires": {
+                "agent-base": "4",
+                "debug": "3.1.0"
+            },
+            "dependencies": {
+                "debug": {
+                    "version": "3.1.0",
+                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+                    "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+                    "dev": true,
+                    "requires": {
+                        "ms": "2.0.0"
+                    }
+                },
+                "ms": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+                    "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+                    "dev": true
+                }
+            }
+        },
+        "https-proxy-agent": {
+            "version": "2.2.4",
+            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
+            "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+            "dev": true,
+            "requires": {
+                "agent-base": "^4.3.0",
+                "debug": "^3.1.0"
+            },
+            "dependencies": {
+                "debug": {
+                    "version": "3.2.6",
+                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+                    "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+                    "dev": true,
+                    "requires": {
+                        "ms": "^2.1.1"
+                    }
+                }
+            }
+        },
         "iconv-lite": {
             "version": "0.4.24",
             "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -992,6 +1287,33 @@
                 }
             }
         },
+        "is-binary-path": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+            "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+            "dev": true,
+            "requires": {
+                "binary-extensions": "^2.0.0"
+            }
+        },
+        "is-buffer": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
+            "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
+            "dev": true
+        },
+        "is-callable": {
+            "version": "1.1.5",
+            "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
+            "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
+            "dev": true
+        },
+        "is-date-object": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
+            "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
+            "dev": true
+        },
         "is-extglob": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1040,6 +1362,24 @@
                 "@types/estree": "0.0.39"
             }
         },
+        "is-regex": {
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
+            "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
+            "dev": true,
+            "requires": {
+                "has": "^1.0.3"
+            }
+        },
+        "is-symbol": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+            "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+            "dev": true,
+            "requires": {
+                "has-symbols": "^1.0.1"
+            }
+        },
         "isexe": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1099,12 +1439,31 @@
                 "uc.micro": "^1.0.1"
             }
         },
+        "locate-path": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+            "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+            "dev": true,
+            "requires": {
+                "p-locate": "^3.0.0",
+                "path-exists": "^3.0.0"
+            }
+        },
         "lodash": {
             "version": "4.17.15",
             "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
             "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
             "dev": true
         },
+        "log-symbols": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
+            "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
+            "dev": true,
+            "requires": {
+                "chalk": "^2.4.2"
+            }
+        },
         "lru-cache": {
             "version": "4.1.5",
             "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@@ -1212,6 +1571,93 @@
                 "minimist": "^1.2.5"
             }
         },
+        "mocha": {
+            "version": "7.1.2",
+            "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz",
+            "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==",
+            "dev": true,
+            "requires": {
+                "ansi-colors": "3.2.3",
+                "browser-stdout": "1.3.1",
+                "chokidar": "3.3.0",
+                "debug": "3.2.6",
+                "diff": "3.5.0",
+                "escape-string-regexp": "1.0.5",
+                "find-up": "3.0.0",
+                "glob": "7.1.3",
+                "growl": "1.10.5",
+                "he": "1.2.0",
+                "js-yaml": "3.13.1",
+                "log-symbols": "3.0.0",
+                "minimatch": "3.0.4",
+                "mkdirp": "0.5.5",
+                "ms": "2.1.1",
+                "node-environment-flags": "1.0.6",
+                "object.assign": "4.1.0",
+                "strip-json-comments": "2.0.1",
+                "supports-color": "6.0.0",
+                "which": "1.3.1",
+                "wide-align": "1.1.3",
+                "yargs": "13.3.2",
+                "yargs-parser": "13.1.2",
+                "yargs-unparser": "1.6.0"
+            },
+            "dependencies": {
+                "debug": {
+                    "version": "3.2.6",
+                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+                    "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+                    "dev": true,
+                    "requires": {
+                        "ms": "^2.1.1"
+                    }
+                },
+                "glob": {
+                    "version": "7.1.3",
+                    "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+                    "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+                    "dev": true,
+                    "requires": {
+                        "fs.realpath": "^1.0.0",
+                        "inflight": "^1.0.4",
+                        "inherits": "2",
+                        "minimatch": "^3.0.4",
+                        "once": "^1.3.0",
+                        "path-is-absolute": "^1.0.0"
+                    }
+                },
+                "mkdirp": {
+                    "version": "0.5.5",
+                    "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+                    "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+                    "dev": true,
+                    "requires": {
+                        "minimist": "^1.2.5"
+                    }
+                },
+                "ms": {
+                    "version": "2.1.1",
+                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+                    "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+                    "dev": true
+                },
+                "strip-json-comments": {
+                    "version": "2.0.1",
+                    "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+                    "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+                    "dev": true
+                },
+                "supports-color": {
+                    "version": "6.0.0",
+                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
+                    "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
+                    "dev": true,
+                    "requires": {
+                        "has-flag": "^3.0.0"
+                    }
+                }
+            }
+        },
         "ms": {
             "version": "2.1.2",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -1236,11 +1682,35 @@
             "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
             "dev": true
         },
+        "node-environment-flags": {
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
+            "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==",
+            "dev": true,
+            "requires": {
+                "object.getownpropertydescriptors": "^2.0.3",
+                "semver": "^5.7.0"
+            },
+            "dependencies": {
+                "semver": {
+                    "version": "5.7.1",
+                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+                    "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+                    "dev": true
+                }
+            }
+        },
         "node-fetch": {
             "version": "2.6.0",
             "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
             "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
         },
+        "normalize-path": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+            "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+            "dev": true
+        },
         "nth-check": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@@ -1250,6 +1720,40 @@
                 "boolbase": "~1.0.0"
             }
         },
+        "object-inspect": {
+            "version": "1.7.0",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
+            "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
+            "dev": true
+        },
+        "object-keys": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+            "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+            "dev": true
+        },
+        "object.assign": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+            "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.2",
+                "function-bind": "^1.1.1",
+                "has-symbols": "^1.0.0",
+                "object-keys": "^1.0.11"
+            }
+        },
+        "object.getownpropertydescriptors": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
+            "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.3",
+                "es-abstract": "^1.17.0-next.1"
+            }
+        },
         "once": {
             "version": "1.4.0",
             "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -1310,6 +1814,30 @@
                 "os-tmpdir": "^1.0.0"
             }
         },
+        "p-limit": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+            "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+            "dev": true,
+            "requires": {
+                "p-try": "^2.0.0"
+            }
+        },
+        "p-locate": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+            "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+            "dev": true,
+            "requires": {
+                "p-limit": "^2.0.0"
+            }
+        },
+        "p-try": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+            "dev": true
+        },
         "parent-module": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -1345,6 +1873,12 @@
                 "@types/node": "*"
             }
         },
+        "path-exists": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+            "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+            "dev": true
+        },
         "path-is-absolute": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
@@ -1419,12 +1953,33 @@
                 "util-deprecate": "^1.0.1"
             }
         },
+        "readdirp": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz",
+            "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==",
+            "dev": true,
+            "requires": {
+                "picomatch": "^2.0.4"
+            }
+        },
         "regexpp": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
             "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
             "dev": true
         },
+        "require-directory": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+            "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+            "dev": true
+        },
+        "require-main-filename": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+            "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+            "dev": true
+        },
         "resolve": {
             "version": "1.16.1",
             "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz",
@@ -1503,6 +2058,12 @@
             "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
             "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
         },
+        "set-blocking": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+            "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+            "dev": true
+        },
         "shebang-command": {
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@@ -1583,6 +2144,48 @@
                 }
             }
         },
+        "string.prototype.trimend": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
+            "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.3",
+                "es-abstract": "^1.17.5"
+            }
+        },
+        "string.prototype.trimleft": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
+            "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.3",
+                "es-abstract": "^1.17.5",
+                "string.prototype.trimstart": "^1.0.0"
+            }
+        },
+        "string.prototype.trimright": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
+            "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.3",
+                "es-abstract": "^1.17.5",
+                "string.prototype.trimend": "^1.0.0"
+            }
+        },
+        "string.prototype.trimstart": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
+            "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
+            "dev": true,
+            "requires": {
+                "define-properties": "^1.1.3",
+                "es-abstract": "^1.17.5"
+            }
+        },
         "string_decoder": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -1865,6 +2468,17 @@
             "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.1.tgz",
             "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg=="
         },
+        "vscode-test": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz",
+            "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==",
+            "dev": true,
+            "requires": {
+                "http-proxy-agent": "^2.1.0",
+                "https-proxy-agent": "^2.2.4",
+                "rimraf": "^2.6.3"
+            }
+        },
         "which": {
             "version": "1.3.1",
             "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
@@ -1874,12 +2488,96 @@
                 "isexe": "^2.0.0"
             }
         },
+        "which-module": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+            "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+            "dev": true
+        },
+        "wide-align": {
+            "version": "1.1.3",
+            "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+            "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+            "dev": true,
+            "requires": {
+                "string-width": "^1.0.2 || 2"
+            },
+            "dependencies": {
+                "ansi-regex": {
+                    "version": "3.0.0",
+                    "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+                    "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+                    "dev": true
+                },
+                "is-fullwidth-code-point": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+                    "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+                    "dev": true
+                },
+                "string-width": {
+                    "version": "2.1.1",
+                    "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+                    "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+                    "dev": true,
+                    "requires": {
+                        "is-fullwidth-code-point": "^2.0.0",
+                        "strip-ansi": "^4.0.0"
+                    }
+                },
+                "strip-ansi": {
+                    "version": "4.0.0",
+                    "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+                    "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+                    "dev": true,
+                    "requires": {
+                        "ansi-regex": "^3.0.0"
+                    }
+                }
+            }
+        },
         "word-wrap": {
             "version": "1.2.3",
             "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
             "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
             "dev": true
         },
+        "wrap-ansi": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
+            "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+            "dev": true,
+            "requires": {
+                "ansi-styles": "^3.2.0",
+                "string-width": "^3.0.0",
+                "strip-ansi": "^5.0.0"
+            },
+            "dependencies": {
+                "emoji-regex": {
+                    "version": "7.0.3",
+                    "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+                    "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+                    "dev": true
+                },
+                "is-fullwidth-code-point": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+                    "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+                    "dev": true
+                },
+                "string-width": {
+                    "version": "3.1.0",
+                    "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+                    "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                    "dev": true,
+                    "requires": {
+                        "emoji-regex": "^7.0.1",
+                        "is-fullwidth-code-point": "^2.0.0",
+                        "strip-ansi": "^5.1.0"
+                    }
+                }
+            }
+        },
         "wrappy": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -1895,12 +2593,82 @@
                 "mkdirp": "^0.5.1"
             }
         },
+        "y18n": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+            "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+            "dev": true
+        },
         "yallist": {
             "version": "2.1.2",
             "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
             "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
             "dev": true
         },
+        "yargs": {
+            "version": "13.3.2",
+            "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
+            "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+            "dev": true,
+            "requires": {
+                "cliui": "^5.0.0",
+                "find-up": "^3.0.0",
+                "get-caller-file": "^2.0.1",
+                "require-directory": "^2.1.1",
+                "require-main-filename": "^2.0.0",
+                "set-blocking": "^2.0.0",
+                "string-width": "^3.0.0",
+                "which-module": "^2.0.0",
+                "y18n": "^4.0.0",
+                "yargs-parser": "^13.1.2"
+            },
+            "dependencies": {
+                "emoji-regex": {
+                    "version": "7.0.3",
+                    "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+                    "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+                    "dev": true
+                },
+                "is-fullwidth-code-point": {
+                    "version": "2.0.0",
+                    "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+                    "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+                    "dev": true
+                },
+                "string-width": {
+                    "version": "3.1.0",
+                    "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+                    "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+                    "dev": true,
+                    "requires": {
+                        "emoji-regex": "^7.0.1",
+                        "is-fullwidth-code-point": "^2.0.0",
+                        "strip-ansi": "^5.1.0"
+                    }
+                }
+            }
+        },
+        "yargs-parser": {
+            "version": "13.1.2",
+            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
+            "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
+            "dev": true,
+            "requires": {
+                "camelcase": "^5.0.0",
+                "decamelize": "^1.2.0"
+            }
+        },
+        "yargs-unparser": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
+            "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==",
+            "dev": true,
+            "requires": {
+                "flat": "^4.1.0",
+                "lodash": "^4.17.15",
+                "yargs": "^13.3.0"
+            }
+        },
         "yauzl": {
             "version": "2.10.0",
             "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
diff --git a/editors/code/package.json b/editors/code/package.json
index d899f60e3..cf66deafb 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -29,8 +29,10 @@
         "package": "vsce package -o rust-analyzer.vsix",
         "build": "tsc",
         "watch": "tsc --watch",
-        "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src",
-        "fix": " tsfmt -r       && eslint -c .eslintrc.js --ext ts ./src --fix"
+        "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src ./tests",
+        "fix": " tsfmt -r       && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
+        "pretest": "npm run build",
+        "test": "node ./out/tests/runTests.js"
     },
     "dependencies": {
         "node-fetch": "^2.6.0",
@@ -39,17 +41,22 @@
     "devDependencies": {
         "@rollup/plugin-commonjs": "^11.1.0",
         "@rollup/plugin-node-resolve": "^7.1.3",
+        "@types/glob": "^7.1.1",
+        "@types/mocha": "^7.0.2",
         "@types/node": "^12.12.39",
         "@types/node-fetch": "^2.5.7",
         "@types/vscode": "^1.44.0",
         "@typescript-eslint/eslint-plugin": "^2.33.0",
         "@typescript-eslint/parser": "^2.33.0",
         "eslint": "^6.8.0",
+        "glob": "^7.1.6",
+        "mocha": "^7.1.2",
         "rollup": "^2.10.0",
         "tslib": "^1.12.0",
         "typescript": "^3.9.2",
         "typescript-formatter": "^7.2.2",
-        "vsce": "^1.75.0"
+        "vsce": "^1.75.0",
+        "vscode-test": "^1.3.0"
     },
     "activationEvents": [
         "onLanguage:rust",
@@ -57,7 +64,7 @@
         "onCommand:rust-analyzer.collectGarbage",
         "workspaceContains:**/Cargo.toml"
     ],
-    "main": "./out/main",
+    "main": "./out/src/main",
     "contributes": {
         "taskDefinitions": [
             {
diff --git a/editors/code/rollup.config.js b/editors/code/rollup.config.js
index 2ca27694d..58360eabb 100644
--- a/editors/code/rollup.config.js
+++ b/editors/code/rollup.config.js
@@ -6,7 +6,7 @@ import nodeBuiltins from 'builtin-modules';
 
 /** @type { import('rollup').RollupOptions } */
 export default {
-    input: 'out/main.js',
+    input: 'out/src/main.js',
     plugins: [
         resolve({
             preferBuiltins: true
@@ -20,7 +20,7 @@ export default {
     ],
     external: [...nodeBuiltins, 'vscode'],
     output: {
-        file: './out/main.js',
+        file: './out/src/main.js',
         format: 'cjs',
         exports: 'named'
     }
diff --git a/editors/code/src/cargo.ts b/editors/code/src/cargo.ts
index 6a41873d0..c3e2e5c05 100644
--- a/editors/code/src/cargo.ts
+++ b/editors/code/src/cargo.ts
@@ -12,14 +12,46 @@ interface CompilationArtifact {
     isTest: boolean;
 }
 
+export interface ArtifactSpec {
+    cargoArgs: string[];
+    filter?: (artifacts: CompilationArtifact[]) => CompilationArtifact[];
+}
+
+export function artifactSpec(args: readonly string[]): ArtifactSpec {
+    const cargoArgs = [...args, "--message-format=json"];
+
+    // arguments for a runnable from the quick pick should be updated.
+    // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens
+    switch (cargoArgs[0]) {
+        case "run": cargoArgs[0] = "build"; break;
+        case "test": {
+            if (cargoArgs.indexOf("--no-run") === -1) {
+                cargoArgs.push("--no-run");
+            }
+            break;
+        }
+    }
+
+    const result: ArtifactSpec = { cargoArgs: cargoArgs };
+    if (cargoArgs[0] === "test") {
+        // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests
+        // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"}
+        result.filter = (artifacts) => {
+            return artifacts.filter(a => a.isTest);
+        };
+    }
+
+    return result;
+}
+
 export class Cargo {
     constructor(readonly rootFolder: string, readonly output: OutputChannel) { }
 
-    private async artifactsFromArgs(cargoArgs: string[]): Promise<CompilationArtifact[]> {
-        const artifacts: CompilationArtifact[] = [];
+    private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> {
+        let artifacts: CompilationArtifact[] = [];
 
         try {
-            await this.runCargo(cargoArgs,
+            await this.runCargo(spec.cargoArgs,
                 message => {
                     if (message.reason === 'compiler-artifact' && message.executable) {
                         const isBinary = message.target.crate_types.includes('bin');
@@ -43,30 +75,15 @@ export class Cargo {
             throw new Error(`Cargo invocation has failed: ${err}`);
         }
 
+        if (spec.filter) {
+            artifacts = spec.filter(artifacts);
+        }
+
         return artifacts;
     }
 
     async executableFromArgs(args: readonly string[]): Promise<string> {
-        const cargoArgs = [...args, "--message-format=json"];
-
-        // arguments for a runnable from the quick pick should be updated.
-        // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens
-        switch (cargoArgs[0]) {
-            case "run": cargoArgs[0] = "build"; break;
-            case "test": {
-                if (cargoArgs.indexOf("--no-run") === -1) {
-                    cargoArgs.push("--no-run");
-                }
-                break;
-            }
-        }
-
-        let artifacts = await this.artifactsFromArgs(cargoArgs);
-        if (cargoArgs[0] === "test") {
-            // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests
-            // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"}
-            artifacts = artifacts.filter(a => a.isTest);
-        }
+        const artifacts = await this.getArtifacts(artifactSpec(args));
 
         if (artifacts.length === 0) {
             throw new Error('No compilation artifacts');
diff --git a/editors/code/tests/runTests.ts b/editors/code/tests/runTests.ts
new file mode 100644
index 000000000..81600f6a8
--- /dev/null
+++ b/editors/code/tests/runTests.ts
@@ -0,0 +1,46 @@
+import * as path from 'path';
+import * as fs from 'fs';
+
+import { runTests } from 'vscode-test';
+
+async function main() {
+    try {
+        // The folder containing the Extension Manifest package.json
+        // Passed to `--extensionDevelopmentPath`
+        const extensionDevelopmentPath = path.resolve(__dirname, '../../');
+
+        // Minimum supported version.
+        const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, 'package.json'));
+        const json = JSON.parse(jsonData.toString());
+        let minimalVersion: string = json.engines.vscode;
+        if (minimalVersion.startsWith('^')) minimalVersion = minimalVersion.slice(1);
+
+        const launchArgs = ["--disable-extensions"];
+
+        // All test suites (either unit tests or integration tests) should be in subfolders.
+        const extensionTestsPath = path.resolve(__dirname, './unit/index');
+
+        // Run tests using the minimal supported version.
+        await runTests({
+            version: minimalVersion,
+            launchArgs,
+            extensionDevelopmentPath,
+            extensionTestsPath
+        });
+
+        // and the latest one
+        await runTests({
+            version: 'stable',
+            launchArgs,
+            extensionDevelopmentPath,
+            extensionTestsPath
+        });
+
+    } catch (err) {
+        // eslint-disable-next-line no-console
+        console.error('Failed to run tests', err);
+        process.exit(1);
+    }
+}
+
+main();
diff --git a/editors/code/tests/unit/index.ts b/editors/code/tests/unit/index.ts
new file mode 100644
index 000000000..1deb1c403
--- /dev/null
+++ b/editors/code/tests/unit/index.ts
@@ -0,0 +1,38 @@
+import * as path from 'path';
+import Mocha from 'mocha';
+import glob from 'glob';
+
+export function run(): Promise<void> {
+    // Create the mocha test
+    const mocha = new Mocha({
+        ui: 'tdd',
+        color: true
+    });
+
+    const testsRoot = __dirname;
+
+    return new Promise((c, e) => {
+        glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
+            if (err) {
+                return e(err);
+            }
+
+            // Add files to the test suite
+            files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
+
+            try {
+                // Run the mocha test
+                mocha.timeout(100000);
+                mocha.run(failures => {
+                    if (failures > 0) {
+                        e(new Error(`${failures} tests failed.`));
+                    } else {
+                        c();
+                    }
+                });
+            } catch (err) {
+                e(err);
+            }
+        });
+    });
+}
diff --git a/editors/code/tests/unit/launch_config.test.ts b/editors/code/tests/unit/launch_config.test.ts
new file mode 100644
index 000000000..d5cf1b74e
--- /dev/null
+++ b/editors/code/tests/unit/launch_config.test.ts
@@ -0,0 +1,52 @@
+import * as assert from 'assert';
+import * as cargo from '../../src/cargo';
+
+suite('Launch configuration', () => {
+
+    suite('Lens', () => {
+        test('A binary', async () => {
+            const args = cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "pkg_name"]);
+
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
+        });
+
+        test('One of Multiple Binaries', async () => {
+            const args = cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "bin1"]);
+
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin1", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
+        });
+
+        test('A test', async () => {
+            const args = cargo.artifactSpec(["test", "--package", "pkg_name", "--lib", "--no-run"]);
+
+            assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--no-run", "--message-format=json"]);
+            assert.notDeepEqual(args.filter, undefined);
+        });
+    });
+
+    suite('QuickPick', () => {
+        test('A binary', async () => {
+            const args = cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "pkg_name"]);
+
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
+        });
+
+
+        test('One of Multiple Binaries', async () => {
+            const args = cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "bin2"]);
+
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin2", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
+        });
+
+        test('A test', async () => {
+            const args = cargo.artifactSpec(["test", "--package", "pkg_name", "--lib"]);
+
+            assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--message-format=json", "--no-run"]);
+            assert.notDeepEqual(args.filter, undefined);
+        });
+    });
+});
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json
index ad134865a..32d1a865f 100644
--- a/editors/code/tsconfig.json
+++ b/editors/code/tsconfig.json
@@ -9,7 +9,7 @@
         "esModuleInterop": true,
         "allowSyntheticDefaultImports": true,
         "sourceMap": true,
-        "rootDir": "src",
+        "rootDir": ".",
         "strict": true,
         "noUnusedLocals": true,
         "noUnusedParameters": true,
@@ -18,6 +18,11 @@
         "newLine": "LF"
     },
     "exclude": [
-        "node_modules"
+        "node_modules",
+        ".vscode-test"
+    ],
+    "include": [
+        "src",
+        "tests"
     ]
 }
-- 
cgit v1.2.3


From c41a10c29331127ee830badddae55f3e27c9a6ea Mon Sep 17 00:00:00 2001
From: vsrs <vit@conrlab.com>
Date: Thu, 21 May 2020 11:34:34 +0300
Subject: Apply suggestions from @Veetaha code review

---
 editors/code/src/cargo.ts        | 14 +++-----
 editors/code/tests/runTests.ts   | 73 +++++++++++++++++++---------------------
 editors/code/tests/unit/index.ts | 10 +++---
 3 files changed, 44 insertions(+), 53 deletions(-)

(limited to 'editors/code')

diff --git a/editors/code/src/cargo.ts b/editors/code/src/cargo.ts
index c3e2e5c05..a55b2f860 100644
--- a/editors/code/src/cargo.ts
+++ b/editors/code/src/cargo.ts
@@ -25,7 +25,7 @@ export function artifactSpec(args: readonly string[]): ArtifactSpec {
     switch (cargoArgs[0]) {
         case "run": cargoArgs[0] = "build"; break;
         case "test": {
-            if (cargoArgs.indexOf("--no-run") === -1) {
+            if (!cargoArgs.includes("--no-run")) {
                 cargoArgs.push("--no-run");
             }
             break;
@@ -36,9 +36,7 @@ export function artifactSpec(args: readonly string[]): ArtifactSpec {
     if (cargoArgs[0] === "test") {
         // for instance, `crates\rust-analyzer\tests\heavy_tests\main.rs` tests
         // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"}
-        result.filter = (artifacts) => {
-            return artifacts.filter(a => a.isTest);
-        };
+        result.filter = (artifacts) => artifacts.filter(it => it.isTest);
     }
 
     return result;
@@ -48,7 +46,7 @@ export class Cargo {
     constructor(readonly rootFolder: string, readonly output: OutputChannel) { }
 
     private async getArtifacts(spec: ArtifactSpec): Promise<CompilationArtifact[]> {
-        let artifacts: CompilationArtifact[] = [];
+        const artifacts: CompilationArtifact[] = [];
 
         try {
             await this.runCargo(spec.cargoArgs,
@@ -75,11 +73,7 @@ export class Cargo {
             throw new Error(`Cargo invocation has failed: ${err}`);
         }
 
-        if (spec.filter) {
-            artifacts = spec.filter(artifacts);
-        }
-
-        return artifacts;
+        return spec.filter?.(artifacts) ?? artifacts;
     }
 
     async executableFromArgs(args: readonly string[]): Promise<string> {
diff --git a/editors/code/tests/runTests.ts b/editors/code/tests/runTests.ts
index 81600f6a8..22df80ad3 100644
--- a/editors/code/tests/runTests.ts
+++ b/editors/code/tests/runTests.ts
@@ -4,43 +4,40 @@ import * as fs from 'fs';
 import { runTests } from 'vscode-test';
 
 async function main() {
-    try {
-        // The folder containing the Extension Manifest package.json
-        // Passed to `--extensionDevelopmentPath`
-        const extensionDevelopmentPath = path.resolve(__dirname, '../../');
-
-        // Minimum supported version.
-        const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, 'package.json'));
-        const json = JSON.parse(jsonData.toString());
-        let minimalVersion: string = json.engines.vscode;
-        if (minimalVersion.startsWith('^')) minimalVersion = minimalVersion.slice(1);
-
-        const launchArgs = ["--disable-extensions"];
-
-        // All test suites (either unit tests or integration tests) should be in subfolders.
-        const extensionTestsPath = path.resolve(__dirname, './unit/index');
-
-        // Run tests using the minimal supported version.
-        await runTests({
-            version: minimalVersion,
-            launchArgs,
-            extensionDevelopmentPath,
-            extensionTestsPath
-        });
-
-        // and the latest one
-        await runTests({
-            version: 'stable',
-            launchArgs,
-            extensionDevelopmentPath,
-            extensionTestsPath
-        });
-
-    } catch (err) {
-        // eslint-disable-next-line no-console
-        console.error('Failed to run tests', err);
-        process.exit(1);
-    }
+    // The folder containing the Extension Manifest package.json
+    // Passed to `--extensionDevelopmentPath`
+    const extensionDevelopmentPath = path.resolve(__dirname, '../../');
+
+    // Minimum supported version.
+    const jsonData = fs.readFileSync(path.join(extensionDevelopmentPath, 'package.json'));
+    const json = JSON.parse(jsonData.toString());
+    let minimalVersion: string = json.engines.vscode;
+    if (minimalVersion.startsWith('^')) minimalVersion = minimalVersion.slice(1);
+
+    const launchArgs = ["--disable-extensions"];
+
+    // All test suites (either unit tests or integration tests) should be in subfolders.
+    const extensionTestsPath = path.resolve(__dirname, './unit/index');
+
+    // Run tests using the minimal supported version.
+    await runTests({
+        version: minimalVersion,
+        launchArgs,
+        extensionDevelopmentPath,
+        extensionTestsPath
+    });
+
+    // and the latest one
+    await runTests({
+        version: 'stable',
+        launchArgs,
+        extensionDevelopmentPath,
+        extensionTestsPath
+    });
 }
 
-main();
+main().catch(err => {
+    // eslint-disable-next-line no-console
+    console.error('Failed to run tests', err);
+    process.exit(1);
+});
diff --git a/editors/code/tests/unit/index.ts b/editors/code/tests/unit/index.ts
index 1deb1c403..5165720b4 100644
--- a/editors/code/tests/unit/index.ts
+++ b/editors/code/tests/unit/index.ts
@@ -11,10 +11,10 @@ export function run(): Promise<void> {
 
     const testsRoot = __dirname;
 
-    return new Promise((c, e) => {
+    return new Promise((resolve, reject) => {
         glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
             if (err) {
-                return e(err);
+                return reject(err);
             }
 
             // Add files to the test suite
@@ -25,13 +25,13 @@ export function run(): Promise<void> {
                 mocha.timeout(100000);
                 mocha.run(failures => {
                     if (failures > 0) {
-                        e(new Error(`${failures} tests failed.`));
+                        reject(new Error(`${failures} tests failed.`));
                     } else {
-                        c();
+                        resolve();
                     }
                 });
             } catch (err) {
-                e(err);
+                reject(err);
             }
         });
     });
-- 
cgit v1.2.3