mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
vscode client side tests
This commit is contained in:
parent
4d3fd62f89
commit
8ee40ccbe9
34
.vscode/launch.json
vendored
34
.vscode/launch.json
vendored
@ -70,6 +70,28 @@
|
||||
"__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer"
|
||||
}
|
||||
},
|
||||
{
|
||||
// Used for testing the extension with a local build of the LSP server (in `target/release`)
|
||||
// with all other extendions loaded.
|
||||
"name": "Run With Extensions",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--disable-extension", "matklad.rust-analyzer",
|
||||
"--extensionDevelopmentPath=${workspaceFolder}/editors/code"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/editors/code/out/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "Build Server (Release) and Extension",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**/*.js"
|
||||
],
|
||||
"env": {
|
||||
"__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer"
|
||||
}
|
||||
},
|
||||
{
|
||||
// Used to attach LLDB to a running LSP server.
|
||||
// NOTE: Might require root permissions. For this run:
|
||||
@ -87,5 +109,17 @@
|
||||
"rust"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Run Unit Tests",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}/editors/code",
|
||||
"--extensionTestsPath=${workspaceFolder}/editors/code/out/tests/unit" ],
|
||||
"sourceMaps": true,
|
||||
"outFiles": [ "${workspaceFolder}/editors/code/out/tests/unit/**/*.js" ],
|
||||
"preLaunchTask": "Pretest"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
12
.vscode/tasks.json
vendored
12
.vscode/tasks.json
vendored
@ -40,6 +40,18 @@
|
||||
"command": "cargo build --release --package rust-analyzer",
|
||||
"problemMatcher": "$rustc"
|
||||
},
|
||||
{
|
||||
"label": "Pretest",
|
||||
"group": "build",
|
||||
"isBackground": false,
|
||||
"type": "npm",
|
||||
"script": "pretest",
|
||||
"path": "editors/code/",
|
||||
"problemMatcher": {
|
||||
"base": "$tsc",
|
||||
"fileLocation": ["relative", "${workspaceFolder}/editors/code/"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"label": "Build Server and Extension",
|
||||
|
@ -1,5 +1,5 @@
|
||||
**
|
||||
!out/main.js
|
||||
!out/src/main.js
|
||||
!package.json
|
||||
!package-lock.json
|
||||
!ra_syntax_tree.tmGrammar.json
|
||||
|
768
editors/code/package-lock.json
generated
768
editors/code/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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": [
|
||||
{
|
||||
|
@ -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'
|
||||
}
|
||||
|
@ -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');
|
||||
|
46
editors/code/tests/runTests.ts
Normal file
46
editors/code/tests/runTests.ts
Normal file
@ -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();
|
38
editors/code/tests/unit/index.ts
Normal file
38
editors/code/tests/unit/index.ts
Normal file
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
52
editors/code/tests/unit/launch_config.test.ts
Normal file
52
editors/code/tests/unit/launch_config.test.ts
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user