blob: d27e97ce29df9a03838dbcdcdce4e8ea19885d37 [file] [log] [blame]
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable node/no-deprecated-api */
/* eslint-disable @typescript-eslint/no-unused-vars */
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------*/
import * as assert from 'assert';
import * as vscode from 'vscode';
import { getGoConfig } from '../../src/config';
import * as lsp from '../../src/goLanguageServer';
import * as goInstallTools from '../../src/goInstallTools';
import { getTool, Tool } from '../../src/goTools';
import { getCheckForToolsUpdatesConfig as getCheckForToolUpdatesConfig } from '../../src/util';
import moment = require('moment');
import semver = require('semver');
import sinon = require('sinon');
suite('getCheckForToolUpdatesConfig tests', () => {
const CHECK_FOR_UPDATES = 'toolsManagement.checkForUpdates';
const LEGACY_CHECK_FOR_UPDATES = 'useGoProxyToCheckForToolUpdates';
const defaultConfigInspector = getGoConfig().inspect(CHECK_FOR_UPDATES);
test('default is as expected', () => {
const { key, defaultValue, globalValue, workspaceValue } = defaultConfigInspector;
assert.deepStrictEqual(
{ key, defaultValue, globalValue, workspaceValue },
{
key: `go.${CHECK_FOR_UPDATES}`,
defaultValue: 'proxy',
globalValue: undefined,
workspaceValue: undefined
},
CHECK_FOR_UPDATES
);
assert.strictEqual(getGoConfig().get(LEGACY_CHECK_FOR_UPDATES), true, LEGACY_CHECK_FOR_UPDATES);
});
// wrapper class of vscode.WorkspaceConfiguration - the object returned by
// vscode.getConfiguration is read-only, and doesn't allow property modification
// so working with sinon directly doesn't seem possible.
class TestWorkspaceConfiguration implements vscode.WorkspaceConfiguration {
constructor(private _wrapped: vscode.WorkspaceConfiguration) {}
public get<T>(params: string) {
return this._wrapped.get<T>(params);
}
public has(params: string) {
return this._wrapped.has(params);
}
public inspect<T>(params: string) {
return this._wrapped.inspect<T>(params);
}
public update<T>(
section: string,
value: any,
configurationTarget?: vscode.ConfigurationTarget | boolean,
overrideInLanguage?: boolean
) {
return this._wrapped.update(section, value, configurationTarget, overrideInLanguage);
}
[key: string]: any;
}
teardown(() => {
sinon.restore();
});
test('default checkForUpdates returns proxy', () => {
const gocfg = getGoConfig();
assert.strictEqual(getCheckForToolUpdatesConfig(gocfg), 'proxy');
});
test('local when new config is not set and legacy config is set to false', () => {
const gocfg = new TestWorkspaceConfiguration(getGoConfig());
sinon.stub(gocfg, 'get').withArgs(LEGACY_CHECK_FOR_UPDATES).returns(false);
assert.strictEqual(getCheckForToolUpdatesConfig(gocfg), 'local');
});
test('proxy when new config is "proxy" and legacy config is set to false', () => {
const gocfg = new TestWorkspaceConfiguration(getGoConfig());
sinon
.stub(gocfg, 'get')
.withArgs(LEGACY_CHECK_FOR_UPDATES)
.returns(false)
.withArgs(CHECK_FOR_UPDATES)
.returns('proxy');
sinon
.stub(gocfg, 'inspect')
.withArgs(CHECK_FOR_UPDATES)
.returns(Object.assign({}, defaultConfigInspector, { globalValue: 'proxy' }));
assert.strictEqual(getCheckForToolUpdatesConfig(gocfg), 'proxy');
});
test('off when new config (workspace) is "off" and legacy config is set to false', () => {
const gocfg = new TestWorkspaceConfiguration(getGoConfig());
sinon
.stub(gocfg, 'get')
.withArgs(LEGACY_CHECK_FOR_UPDATES)
.returns(false)
.withArgs(CHECK_FOR_UPDATES)
.returns('off');
sinon
.stub(gocfg, 'inspect')
.withArgs(CHECK_FOR_UPDATES)
.returns(Object.assign({}, defaultConfigInspector, { workspaceValue: 'off' }));
assert.strictEqual(getCheckForToolUpdatesConfig(gocfg), 'off');
});
});
suite('gopls update tests', () => {
test('prompt for update', async () => {
const tool = getTool('gopls');
const toSemver = (v: string) => semver.parse(v, { includePrerelease: true, loose: true });
// Fake data stubbed functions will serve.
const latestVersion = toSemver('0.4.1');
const latestVersionTimestamp = moment('2020-05-13', 'YYYY-MM-DD');
const latestPrereleaseVersion = toSemver('0.4.2-pre1');
const latestPrereleaseVersionTimestamp = moment('2020-05-20', 'YYYY-MM-DD');
// name, usersVersion, acceptPrerelease, want
const testCases: [string, string, boolean, semver.SemVer][] = [
['outdated, tagged', 'v0.3.1', false, latestVersion],
['outdated, tagged (pre-release)', '0.3.1', true, latestPrereleaseVersion],
['up-to-date, tagged', latestVersion.format(), false, null],
['up-to-date tagged (pre-release)', 'v0.4.0', true, latestPrereleaseVersion],
['developer version', '(devel)', false, null],
['developer version (pre-release)', '(devel)', true, null],
['nonsense version', 'nosuchversion', false, latestVersion],
['nonsense version (pre-release)', 'nosuchversion', true, latestPrereleaseVersion],
['latest pre-release', 'v0.4.2-pre1', false, null],
['latest pre-release (pre-release)', 'v0.4.2-pre1', true, null],
['outdated pre-release version', 'v0.3.1-pre1', false, latestVersion],
['outdated pre-release version (pre-release)', 'v0.3.1-pre1', true, latestPrereleaseVersion],
['recent pseudoversion after pre-release, 2020-05-20', 'v0.0.0-20200521000000-2212a7e161a5', false, null],
['recent pseudoversion before pre-release, 2020-05-20', 'v0.0.0-20200515000000-2212a7e161a5', false, null],
['recent pseudoversion after pre-release (pre-release)', 'v0.0.0-20200521000000-2212a7e161a5', true, null],
[
'recent pseudoversion before pre-release (pre-release)',
'v0.0.0-20200515000000-2212a7e161a5',
true,
latestPrereleaseVersion
],
['outdated pseudoversion', 'v0.0.0-20200309030707-2212a7e161a5', false, latestVersion],
[
'outdated pseudoversion (pre-release)',
'v0.0.0-20200309030707-2212a7e161a5',
true,
latestPrereleaseVersion
]
];
for (const [name, usersVersion, acceptPrerelease, want] of testCases) {
sinon.replace(lsp, 'getLocalGoplsVersion', async () => {
return usersVersion;
});
sinon.replace(goInstallTools, 'latestToolVersion', async () => {
if (acceptPrerelease) {
return latestPrereleaseVersion;
}
return latestVersion;
});
sinon.replace(lsp, 'getTimestampForVersion', async (_: Tool, version: semver.SemVer) => {
if (version === latestVersion) {
return latestVersionTimestamp;
}
if (version === latestPrereleaseVersion) {
return latestPrereleaseVersionTimestamp;
}
});
const got = await lsp.shouldUpdateLanguageServer(tool, {
enabled: true,
path: 'bad/path/to/gopls',
version: '',
checkForUpdates: 'proxy',
env: {},
features: {
diagnostics: true
},
flags: [],
modtime: new Date(),
serverName: 'gopls'
});
assert.deepEqual(got, want, `${name}: failed (got: '${got}' ${typeof got} want: '${want}' ${typeof want})`);
sinon.restore();
}
});
});
suite('version comparison', () => {
const tool = getTool('dlv-dap');
const latestVersion = tool.latestVersion;
teardown(() => {
sinon.restore();
});
async function testShouldUpdateTool(expected: boolean, moduleVersion?: string) {
sinon.stub(goInstallTools, 'inspectGoToolVersion').returns(Promise.resolve({ moduleVersion }));
const got = await goInstallTools.shouldUpdateTool(tool, '/bin/path/to/dlv-dap');
assert.strictEqual(
expected,
got,
`hard-coded minimum: ${tool.latestVersion.toString()} vs localVersion: ${moduleVersion}`
);
}
test('local delve is old', async () => {
await testShouldUpdateTool(true, 'v1.6.0');
});
test('local delve is the minimum required version', async () => {
await testShouldUpdateTool(false, 'v' + latestVersion.toString());
});
test('local delve is newer', async () => {
await testShouldUpdateTool(false, `v${latestVersion.major}.${latestVersion.minor + 1}.0`);
});
test('local delve is slightly older', async () => {
await testShouldUpdateTool(
true,
`v${latestVersion.major}.${latestVersion.minor}.${latestVersion.patch}-0.20201231000000-5360c6286949`
);
});
test('local delve is slightly newer', async () => {
await testShouldUpdateTool(
false,
`v{$latestVersion.major}.${latestVersion.minor}.${latestVersion.patch}-0.30211231000000-5360c6286949`
);
});
test('local delve version is unknown', async () => {
// maybe a wrapper shellscript?
await testShouldUpdateTool(false, undefined);
});
test('local delve version is non-sense', async () => {
// maybe a wrapper shellscript?
await testShouldUpdateTool(false, 'hello');
});
test('local delve version is non-sense again', async () => {
// maybe a wrapper shellscript?
await testShouldUpdateTool(false, '');
});
});