Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ function showFunctionDetails(
detailsChannel.show(true /* preserveFocus */);
}

/**
* Validates the current configuration and, if the thresholds are misconfigured
* (e.g. warningThreshold >= errorThreshold), surfaces a warning to the user so
* the issue isn't silently ignored.
*
* Exported for unit-testing purposes.
*/
export function checkConfigurationValidity(): void {
const { valid, warnings } = ConfigurationManager.validateConfiguration();
if (!valid) {
vscode.window.showWarningMessage(
`Code Metrics: invalid configuration detected. ${warnings.join(" ")}`
);
}
}

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
Expand All @@ -69,7 +85,17 @@ export function activate(context: vscode.ExtensionContext) {
// Register providers
const codeLensDisposable = registerCodeLensProvider();

context.subscriptions.push(showFunctionDetailsCommand, codeLensDisposable);
// Warn the user up front, and again whenever settings change, if thresholds are invalid.
checkConfigurationValidity();
const configValidityWatcher = ConfigurationManager.onConfigurationChanged(() => {
checkConfigurationValidity();
Comment on lines +89 to +91
});

context.subscriptions.push(
showFunctionDetailsCommand,
codeLensDisposable,
configValidityWatcher
);
}

// This method is called when your extension is deactivated
Expand Down
85 changes: 85 additions & 0 deletions src/test/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,89 @@ suite("Extension Activation Tests", () => {
extensionModule.deactivate();
}, "deactivate() should not throw");
});

suite("checkConfigurationValidity", () => {
// Stub type to capture showWarningMessage calls
type ShowWarningStub = (message: string, ...items: string[]) => Thenable<string | undefined>;

let warningMessages: string[];
let originalShowWarningMessage: typeof vscode.window.showWarningMessage;

setup(() => {
warningMessages = [];
originalShowWarningMessage = vscode.window.showWarningMessage;
(vscode.window as any).showWarningMessage = ((message: string) => {
warningMessages.push(message);
return Promise.resolve(undefined);
}) as ShowWarningStub;
});

teardown(async () => {
(vscode.window as any).showWarningMessage = originalShowWarningMessage;
const vsConfig = vscode.workspace.getConfiguration("codeMetrics");
await vsConfig.update("warningThreshold", undefined, vscode.ConfigurationTarget.Global);
await vsConfig.update("errorThreshold", undefined, vscode.ConfigurationTarget.Global);
});
Comment on lines +167 to +172

test("should not show a warning when thresholds are valid", () => {
// Default configuration has valid thresholds (warningThreshold < errorThreshold)
extensionModule.checkConfigurationValidity();

assert.strictEqual(
warningMessages.length,
0,
"No warning should be shown for valid configuration"
);
});

test("should show a warning when warningThreshold equals errorThreshold", async () => {
const vsConfig = vscode.workspace.getConfiguration("codeMetrics");
await vsConfig.update("warningThreshold", 10, vscode.ConfigurationTarget.Global);
await vsConfig.update("errorThreshold", 10, vscode.ConfigurationTarget.Global);

// Reset captured messages so that onConfigurationChanged calls from the
// config updates above don't pollute the assertion.
warningMessages = [];
extensionModule.checkConfigurationValidity();

assert.strictEqual(
warningMessages.length,
1,
"Exactly one warning should be shown"
);
assert.ok(
warningMessages[0].includes("Code Metrics"),
"Warning message should be prefixed with 'Code Metrics'"
);
assert.ok(
warningMessages[0].includes("invalid configuration"),
"Warning message should mention invalid configuration"
);
});

test("should show a warning when warningThreshold exceeds errorThreshold", async () => {
const vsConfig = vscode.workspace.getConfiguration("codeMetrics");
await vsConfig.update("warningThreshold", 20, vscode.ConfigurationTarget.Global);
await vsConfig.update("errorThreshold", 10, vscode.ConfigurationTarget.Global);

// Reset captured messages so that onConfigurationChanged calls from the
// config updates above don't pollute the assertion.
warningMessages = [];
extensionModule.checkConfigurationValidity();

assert.strictEqual(
warningMessages.length,
1,
"Exactly one warning should be shown"
);
assert.ok(
warningMessages[0].includes("Warning threshold (20)"),
"Warning message should include the invalid warningThreshold value"
);
assert.ok(
warningMessages[0].includes("error threshold (10)"),
"Warning message should include the errorThreshold value"
);
});
});
});