Skip to content

Commit b9be9cf

Browse files
committed
Add new class and helper for setting test config values
This class will be used to set test config values for the tests. It is able to set the config value to a specified value for every test and restore the value to the original value after the test.
1 parent 8c5d73b commit b9be9cf

File tree

3 files changed

+99
-2
lines changed

3 files changed

+99
-2
lines changed

extensions/ql-vscode/src/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ const REMOTE_QUERIES_SETTING = new Setting('variantAnalysis', ROOT_SETTING);
332332
* This setting should be a JSON object where each key is a user-specified name (string),
333333
* and the value is an array of GitHub repositories (of the form `<owner>/<repo>`).
334334
*/
335-
const REMOTE_REPO_LISTS = new Setting('repositoryLists', REMOTE_QUERIES_SETTING);
335+
export const REMOTE_REPO_LISTS = new Setting('repositoryLists', REMOTE_QUERIES_SETTING);
336336

337337
export function getRemoteRepositoryLists(): Record<string, string[]> | undefined {
338338
return REMOTE_REPO_LISTS.getValue<Record<string, string[]>>() || undefined;
@@ -363,7 +363,7 @@ export function getRemoteRepositoryListsPath(): string | undefined {
363363
*
364364
* This setting should be a GitHub repository of the form `<owner>/<repo>`.
365365
*/
366-
const REMOTE_CONTROLLER_REPO = new Setting('controllerRepo', REMOTE_QUERIES_SETTING);
366+
export const REMOTE_CONTROLLER_REPO = new Setting('controllerRepo', REMOTE_QUERIES_SETTING);
367367

368368
export function getRemoteControllerRepo(): string | undefined {
369369
return REMOTE_CONTROLLER_REPO.getValue<string>() || undefined;

extensions/ql-vscode/src/vscode-tests/index-template.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as Mocha from 'mocha';
33
import * as glob from 'glob-promise';
44
import { ensureCli } from './ensureCli';
55
import { env } from 'vscode';
6+
import { testConfigHelper } from './test-config';
67

78

89
// Use this handler to avoid swallowing unhandled rejections.
@@ -69,6 +70,9 @@ export async function runTestsInDirectory(testsRoot: string, useCli = false): Pr
6970
mocha.addFile(path.resolve(testsRoot, f));
7071
});
7172

73+
// Setup the config helper. This needs to run before other helpers so any config they setup
74+
// is restored.
75+
await testConfigHelper(mocha);
7276

7377
// Add helpers. Helper files add global setup and teardown blocks
7478
// for a test run.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { ConfigurationTarget, workspace } from 'vscode';
2+
import { CUSTOM_CODEQL_PATH_SETTING, REMOTE_CONTROLLER_REPO, REMOTE_REPO_LISTS, Setting } from '../config';
3+
4+
class TestSetting<T> {
5+
private settingState: {
6+
globalValue?: T;
7+
workspaceValue?: T,
8+
workspaceFolderValue?: T,
9+
} | undefined;
10+
11+
constructor(
12+
public readonly setting: Setting,
13+
private initialTestValue: T | undefined = undefined
14+
) { }
15+
16+
public async get(): Promise<T | undefined> {
17+
return this.section.get(this.setting.name);
18+
}
19+
20+
public async set(value: T | undefined, target: ConfigurationTarget = ConfigurationTarget.Global): Promise<void> {
21+
await this.section.update(this.setting.name, value, target);
22+
}
23+
24+
public async setInitialTestValue(value: T | undefined) {
25+
this.initialTestValue = value;
26+
}
27+
28+
public async initialSetup() {
29+
this.settingState = this.section.inspect(this.setting.name);
30+
31+
// Unfortunately it's not well-documented how to check whether we can write to a workspace
32+
// configuration. This is the best I could come up with. It only fails for initial test values
33+
// which are not undefined.
34+
if (this.settingState?.workspaceValue !== undefined) {
35+
await this.set(this.initialTestValue, ConfigurationTarget.Workspace);
36+
}
37+
if (this.settingState?.workspaceFolderValue !== undefined) {
38+
await this.set(this.initialTestValue, ConfigurationTarget.WorkspaceFolder);
39+
}
40+
41+
await this.setup();
42+
}
43+
44+
public async setup() {
45+
await this.set(this.initialTestValue, ConfigurationTarget.Global);
46+
}
47+
48+
public async restoreToInitialValues() {
49+
const state = this.section.inspect(this.setting.name);
50+
51+
// We need to check the state of the setting before we restore it. This is less important for the global
52+
// configuration target, but the workspace/workspace folder configuration might not even exist. If they
53+
// don't exist, VSCode will error when trying to write the new value (even if that value is undefined).
54+
if (state?.globalValue !== this.settingState?.globalValue) {
55+
await this.set(this.settingState?.globalValue, ConfigurationTarget.Global);
56+
}
57+
if (state?.workspaceValue !== this.settingState?.workspaceValue) {
58+
await this.set(this.settingState?.workspaceValue, ConfigurationTarget.Workspace);
59+
}
60+
if (state?.workspaceFolderValue !== this.settingState?.workspaceFolderValue) {
61+
await this.set(this.settingState?.workspaceFolderValue, ConfigurationTarget.WorkspaceFolder);
62+
}
63+
}
64+
65+
private get section() {
66+
if (this.setting.parent === undefined) {
67+
throw new Error('Cannot get the value of a root setting.');
68+
}
69+
return workspace.getConfiguration(this.setting.parent.qualifiedName);
70+
}
71+
}
72+
73+
export const testConfig = {
74+
remoteControllerRepo: new TestSetting<string>(REMOTE_CONTROLLER_REPO),
75+
remoteRepoLists: new TestSetting<Record<string, string[]>>(REMOTE_REPO_LISTS),
76+
cliExecutablePath: new TestSetting<string>(CUSTOM_CODEQL_PATH_SETTING),
77+
};
78+
79+
export const testConfigHelper = async (mocha: Mocha) => {
80+
// Read in all current settings
81+
await Promise.all(Object.values(testConfig).map(setting => setting.initialSetup()));
82+
83+
mocha.rootHooks({
84+
async beforeEach() {
85+
// Reset the settings to their initial values before each test
86+
await Promise.all(Object.values(testConfig).map(setting => setting.setup()));
87+
},
88+
async afterAll() {
89+
// Restore all settings to their default values after each test suite
90+
await Promise.all(Object.values(testConfig).map(setting => setting.restoreToInitialValues()));
91+
}
92+
});
93+
};

0 commit comments

Comments
 (0)