Merge branch 'main' into elena/disable-local-retry

This commit is contained in:
Elena Tanasoiu
2023-03-23 15:36:33 +00:00
committed by GitHub
11 changed files with 210 additions and 155 deletions

View File

@@ -72,6 +72,20 @@
override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
}
/**
* A usage of a command from the typescript code, by calling `CommandManager.execute`.
*/
class CommandUsageCommandManagerMethodCallExpr extends CommandUsage, MethodCallExpr {
CommandUsageCommandManagerMethodCallExpr() {
this.getCalleeName() = "execute" and
this.getReceiver().getType().unfold().(TypeReference).getTypeName().getName() = "CommandManager" and
this.getArgument(0).(StringLiteral).getValue().matches("%codeQL%") and
not this.getFile().getRelativePath().matches("extensions/ql-vscode/test/%")
}
override string getCommandName() { result = this.getArgument(0).(StringLiteral).getValue() }
}
/**
* A usage of a command from any menu that isn't the command palette.

View File

@@ -54,7 +54,7 @@
"@babel/core": "^7.18.13",
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
"@faker-js/faker": "^7.5.0",
"@octokit/plugin-throttling": "^4.3.2",
"@octokit/plugin-throttling": "^5.0.1",
"@storybook/addon-actions": "^6.5.10",
"@storybook/addon-essentials": "^6.5.10",
"@storybook/addon-interactions": "^6.5.10",
@@ -5592,12 +5592,12 @@
}
},
"node_modules/@octokit/plugin-throttling": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-4.3.2.tgz",
"integrity": "sha512-ZaCK599h3tzcoy0Jtdab95jgmD7X9iAk59E2E7hYKCAmnURaI4WpzwL9vckImilybUGrjY1JOWJapDs2N2D3vw==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-5.0.1.tgz",
"integrity": "sha512-I4qxs7wYvYlFuY3PAUGWAVPhFXG3RwnvTiSr5Fu/Auz7bYhDLnzS2MjwV8nGLq/FPrWwYiweeZrI5yjs1YG4tQ==",
"dev": true,
"dependencies": {
"@octokit/types": "^8.0.0",
"@octokit/types": "^9.0.0",
"bottleneck": "^2.15.3"
},
"engines": {
@@ -5608,18 +5608,18 @@
}
},
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==",
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==",
"dev": true
},
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"dev": true,
"dependencies": {
"@octokit/openapi-types": "^14.0.0"
"@octokit/openapi-types": "^16.0.0"
}
},
"node_modules/@octokit/request": {
@@ -45277,28 +45277,28 @@
}
},
"@octokit/plugin-throttling": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-4.3.2.tgz",
"integrity": "sha512-ZaCK599h3tzcoy0Jtdab95jgmD7X9iAk59E2E7hYKCAmnURaI4WpzwL9vckImilybUGrjY1JOWJapDs2N2D3vw==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-5.0.1.tgz",
"integrity": "sha512-I4qxs7wYvYlFuY3PAUGWAVPhFXG3RwnvTiSr5Fu/Auz7bYhDLnzS2MjwV8nGLq/FPrWwYiweeZrI5yjs1YG4tQ==",
"dev": true,
"requires": {
"@octokit/types": "^8.0.0",
"@octokit/types": "^9.0.0",
"bottleneck": "^2.15.3"
},
"dependencies": {
"@octokit/openapi-types": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-14.0.0.tgz",
"integrity": "sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==",
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==",
"dev": true
},
"@octokit/types": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-8.0.0.tgz",
"integrity": "sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"dev": true,
"requires": {
"@octokit/openapi-types": "^14.0.0"
"@octokit/openapi-types": "^16.0.0"
}
}
}

View File

@@ -1475,7 +1475,7 @@
"@babel/core": "^7.18.13",
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
"@faker-js/faker": "^7.5.0",
"@octokit/plugin-throttling": "^4.3.2",
"@octokit/plugin-throttling": "^5.0.1",
"@storybook/addon-actions": "^6.5.10",
"@storybook/addon-essentials": "^6.5.10",
"@storybook/addon-interactions": "^6.5.10",

View File

@@ -38,6 +38,7 @@ export type BuiltInVsCodeCommands = {
// The codeQLDatabases.focus command is provided by VS Code because we've registered the custom view
"codeQLDatabases.focus": () => Promise<void>;
"markdown.showPreviewToSide": (uri: Uri) => Promise<void>;
revealFileInOS: (uri: Uri) => Promise<void>;
setContext: (
key: `${"codeql" | "codeQL"}${string}`,
value: unknown,

View File

@@ -777,6 +777,7 @@ async function activateWithInstalledDistribution(
};
const qhm = new QueryHistoryManager(
app,
qs,
dbm,
localQueryResultsView,

View File

@@ -1,6 +1,5 @@
import { join, dirname } from "path";
import {
commands,
Disposable,
env,
EventEmitter,
@@ -26,12 +25,7 @@ import { extLogger } from "../common";
import { URLSearchParams } from "url";
import { DisposableObject } from "../pure/disposable-object";
import { ONE_HOUR_IN_MS, TWO_HOURS_IN_MS } from "../pure/time";
import {
asError,
assertNever,
getErrorMessage,
getErrorStack,
} from "../pure/helpers-pure";
import { asError, assertNever, getErrorMessage } from "../pure/helpers-pure";
import { CompletedLocalQueryInfo, LocalQueryInfo } from "../query-results";
import {
getActionsWorkflowRunUrl,
@@ -66,6 +60,8 @@ import { HistoryTreeDataProvider } from "./history-tree-data-provider";
import { redactableError } from "../pure/errors";
import { QueryHistoryDirs } from "./query-history-dirs";
import { QueryHistoryCommands } from "../common/commands";
import { App } from "../common/app";
import { tryOpenExternalFile } from "../vscode-utils/external-files";
/**
* query-history-manager.ts
@@ -135,6 +131,7 @@ export class QueryHistoryManager extends DisposableObject {
readonly onDidCompleteQuery = this._onDidCompleteQuery.event;
constructor(
private readonly app: App,
private readonly qs: QueryRunner,
private readonly dbm: DatabaseManager,
private readonly localQueriesResultsView: ResultsView,
@@ -683,7 +680,10 @@ export class QueryHistoryManager extends DisposableObject {
}
if (singleItem.completedQuery.logFileLocation) {
await this.tryOpenExternalFile(singleItem.completedQuery.logFileLocation);
await tryOpenExternalFile(
this.app.commands,
singleItem.completedQuery.logFileLocation,
);
} else {
void showAndLogWarningMessage("No log file available");
}
@@ -751,7 +751,7 @@ export class QueryHistoryManager extends DisposableObject {
}
}
try {
await commands.executeCommand(
await this.app.commands.execute(
"revealFileInOS",
Uri.file(externalFilePath),
);
@@ -800,7 +800,10 @@ export class QueryHistoryManager extends DisposableObject {
}
if (finalSingleItem.evalLogLocation) {
await this.tryOpenExternalFile(finalSingleItem.evalLogLocation);
await tryOpenExternalFile(
this.app.commands,
finalSingleItem.evalLogLocation,
);
} else {
this.warnNoEvalLogs();
}
@@ -825,7 +828,10 @@ export class QueryHistoryManager extends DisposableObject {
}
if (finalSingleItem.evalLogSummaryLocation) {
await this.tryOpenExternalFile(finalSingleItem.evalLogSummaryLocation);
await tryOpenExternalFile(
this.app.commands,
finalSingleItem.evalLogSummaryLocation,
);
return;
}
@@ -968,7 +974,10 @@ export class QueryHistoryManager extends DisposableObject {
const query = finalSingleItem.completedQuery.query;
const hasInterpretedResults = query.canHaveInterpretedResults();
if (hasInterpretedResults) {
await this.tryOpenExternalFile(query.resultsPaths.interpretedResultsPath);
await tryOpenExternalFile(
this.app.commands,
query.resultsPaths.interpretedResultsPath,
);
} else {
const label = this.labelProvider.getLabel(finalSingleItem);
void showAndLogInformationMessage(
@@ -997,11 +1006,11 @@ export class QueryHistoryManager extends DisposableObject {
}
const query = finalSingleItem.completedQuery.query;
if (await query.hasCsv()) {
void this.tryOpenExternalFile(query.csvPath);
void tryOpenExternalFile(this.app.commands, query.csvPath);
return;
}
if (await query.exportCsvResults(this.qs.cliServer, query.csvPath)) {
void this.tryOpenExternalFile(query.csvPath);
void tryOpenExternalFile(this.app.commands, query.csvPath);
}
}
@@ -1024,7 +1033,8 @@ export class QueryHistoryManager extends DisposableObject {
return;
}
await this.tryOpenExternalFile(
await tryOpenExternalFile(
this.app.commands,
await finalSingleItem.completedQuery.query.ensureCsvAlerts(
this.qs.cliServer,
this.dbm,
@@ -1051,7 +1061,8 @@ export class QueryHistoryManager extends DisposableObject {
return;
}
await this.tryOpenExternalFile(
await tryOpenExternalFile(
this.app.commands,
await finalSingleItem.completedQuery.query.ensureDilPath(
this.qs.cliServer,
),
@@ -1077,7 +1088,7 @@ export class QueryHistoryManager extends DisposableObject {
const actionsWorkflowRunUrl = getActionsWorkflowRunUrl(finalSingleItem);
await commands.executeCommand(
await this.app.commands.execute(
"vscode.open",
Uri.parse(actionsWorkflowRunUrl),
);
@@ -1101,7 +1112,7 @@ export class QueryHistoryManager extends DisposableObject {
return;
}
await commands.executeCommand(
await this.app.commands.execute(
"codeQL.copyVariantAnalysisRepoList",
finalSingleItem.variantAnalysis.id,
);
@@ -1171,47 +1182,6 @@ export class QueryHistoryManager extends DisposableObject {
}
}
private async tryOpenExternalFile(fileLocation: string) {
const uri = Uri.file(fileLocation);
try {
await window.showTextDocument(uri, { preview: false });
} catch (e) {
const msg = getErrorMessage(e);
if (
msg.includes(
"Files above 50MB cannot be synchronized with extensions",
) ||
msg.includes("too large to open")
) {
const res = await showBinaryChoiceDialog(
`VS Code does not allow extensions to open files >50MB. This file
exceeds that limit. Do you want to open it outside of VS Code?
You can also try manually opening it inside VS Code by selecting
the file in the file explorer and dragging it into the workspace.`,
);
if (res) {
try {
await commands.executeCommand("revealFileInOS", uri);
} catch (e) {
void showAndLogExceptionWithTelemetry(
redactableError(
asError(e),
)`Failed to reveal file in OS: ${getErrorMessage(e)}`,
);
}
}
} else {
void showAndLogExceptionWithTelemetry(
redactableError(asError(e))`Could not open file ${fileLocation}`,
{
fullMessage: `${getErrorMessage(e)}\n${getErrorStack(e)}`,
},
);
}
}
}
private async findOtherQueryToCompare(
singleItem: QueryHistoryInfo,
multiSelect: QueryHistoryInfo[],

View File

@@ -0,0 +1,50 @@
import { Uri, window } from "vscode";
import { AppCommandManager } from "../common/commands";
import {
showAndLogExceptionWithTelemetry,
showBinaryChoiceDialog,
} from "../helpers";
import { redactableError } from "../pure/errors";
import { asError, getErrorMessage, getErrorStack } from "../pure/helpers-pure";
export async function tryOpenExternalFile(
commandManager: AppCommandManager,
fileLocation: string,
) {
const uri = Uri.file(fileLocation);
try {
await window.showTextDocument(uri, { preview: false });
} catch (e) {
const msg = getErrorMessage(e);
if (
msg.includes("Files above 50MB cannot be synchronized with extensions") ||
msg.includes("too large to open")
) {
const res = await showBinaryChoiceDialog(
`VS Code does not allow extensions to open files >50MB. This file
exceeds that limit. Do you want to open it outside of VS Code?
You can also try manually opening it inside VS Code by selecting
the file in the file explorer and dragging it into the workspace.`,
);
if (res) {
try {
await commandManager.execute("revealFileInOS", uri);
} catch (e) {
void showAndLogExceptionWithTelemetry(
redactableError(
asError(e),
)`Failed to reveal file in OS: ${getErrorMessage(e)}`,
);
}
}
} else {
void showAndLogExceptionWithTelemetry(
redactableError(asError(e))`Could not open file ${fileLocation}`,
{
fullMessage: `${getErrorMessage(e)}\n${getErrorStack(e)}`,
},
);
}
}
}

View File

@@ -27,6 +27,7 @@ import {
} from "../../../../src/query-history/history-tree-data-provider";
import { QueryHistoryManager } from "../../../../src/query-history/query-history-manager";
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
import { createMockApp } from "../../../__mocks__/appMock";
describe("HistoryTreeDataProvider", () => {
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
@@ -421,6 +422,7 @@ describe("HistoryTreeDataProvider", () => {
async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) {
const qhm = new QueryHistoryManager(
createMockApp({}),
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

View File

@@ -22,59 +22,49 @@ import { createMockVariantAnalysisHistoryItem } from "../../../factories/query-h
import { VariantAnalysisHistoryItem } from "../../../../src/query-history/variant-analysis-history-item";
import { QueryStatus } from "../../../../src/query-status";
import { VariantAnalysisStatus } from "../../../../src/variant-analysis/shared/variant-analysis";
import { TextEditor } from "vscode";
import { WebviewReveal } from "../../../../src/interface-utils";
import * as helpers from "../../../../src/helpers";
import { mockedObject, mockedQuickPickItem } from "../../utils/mocking.helpers";
import { mockedQuickPickItem } from "../../utils/mocking.helpers";
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
import { createMockApp } from "../../../__mocks__/appMock";
import { App } from "../../../../src/common/app";
import { createMockCommandManager } from "../../../__mocks__/commandsMock";
describe("QueryHistoryManager", () => {
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
let configListener: QueryHistoryConfigListener;
let showTextDocumentSpy: jest.SpiedFunction<
typeof vscode.window.showTextDocument
>;
let showInformationMessageSpy: jest.SpiedFunction<
typeof vscode.window.showInformationMessage
>;
let showQuickPickSpy: jest.SpiedFunction<typeof vscode.window.showQuickPick>;
let executeCommandSpy: jest.SpiedFunction<
typeof vscode.commands.executeCommand
>;
let cancelVariantAnalysisSpy: jest.SpiedFunction<
typeof variantAnalysisManagerStub.cancelVariantAnalysis
>;
const doCompareCallback = jest.fn();
let executeCommand: jest.MockedFn<
(commandName: string, ...args: any[]) => Promise<any>
>;
let mockApp: App;
let queryHistoryManager: QueryHistoryManager;
let localQueriesResultsViewStub: ResultsView;
let variantAnalysisManagerStub: VariantAnalysisManager;
let tryOpenExternalFile: Function;
let allHistory: QueryHistoryInfo[];
let localQueryHistory: LocalQueryInfo[];
let variantAnalysisHistory: VariantAnalysisHistoryItem[];
beforeEach(() => {
showTextDocumentSpy = jest
.spyOn(vscode.window, "showTextDocument")
.mockResolvedValue(mockedObject<TextEditor>({}));
showInformationMessageSpy = jest
.spyOn(vscode.window, "showInformationMessage")
.mockResolvedValue(undefined);
showQuickPickSpy = jest
.spyOn(vscode.window, "showQuickPick")
.mockResolvedValue(undefined);
executeCommandSpy = jest
.spyOn(vscode.commands, "executeCommand")
.mockResolvedValue(undefined);
executeCommand = jest.fn();
mockApp = createMockApp({
commands: createMockCommandManager({ executeCommand }),
});
jest.spyOn(extLogger, "log").mockResolvedValue(undefined);
tryOpenExternalFile = (QueryHistoryManager.prototype as any)
.tryOpenExternalFile;
configListener = new QueryHistoryConfigListener();
localQueriesResultsViewStub = {
showResults: jest.fn(),
@@ -157,51 +147,6 @@ describe("QueryHistoryManager", () => {
queryHistoryManager.dispose();
}
});
describe("tryOpenExternalFile", () => {
it("should open an external file", async () => {
await tryOpenExternalFile("xxx");
expect(showTextDocumentSpy).toHaveBeenCalledTimes(1);
expect(showTextDocumentSpy).toHaveBeenCalledWith(
vscode.Uri.file("xxx"),
expect.anything(),
);
expect(executeCommandSpy).not.toBeCalled();
});
[
"too large to open",
"Files above 50MB cannot be synchronized with extensions",
].forEach((msg) => {
it(`should fail to open a file because "${msg}" and open externally`, async () => {
showTextDocumentSpy.mockRejectedValue(new Error(msg));
showInformationMessageSpy.mockResolvedValue({ title: "Yes" });
await tryOpenExternalFile("xxx");
const uri = vscode.Uri.file("xxx");
expect(showTextDocumentSpy).toHaveBeenCalledTimes(1);
expect(showTextDocumentSpy).toHaveBeenCalledWith(
uri,
expect.anything(),
);
expect(executeCommandSpy).toHaveBeenCalledWith("revealFileInOS", uri);
});
it(`should fail to open a file because "${msg}" and NOT open externally`, async () => {
showTextDocumentSpy.mockRejectedValue(new Error(msg));
showInformationMessageSpy.mockResolvedValue({ title: "No" });
await tryOpenExternalFile("xxx");
const uri = vscode.Uri.file("xxx");
expect(showTextDocumentSpy).toHaveBeenCalledTimes(1);
expect(showTextDocumentSpy).toHaveBeenCalledWith(
uri,
expect.anything(),
);
expect(showInformationMessageSpy).toBeCalled();
expect(executeCommandSpy).not.toBeCalled();
});
});
});
describe("handleItemClicked", () => {
describe("single click", () => {
@@ -832,7 +777,7 @@ describe("QueryHistoryManager", () => {
const item = localQueryHistory[4];
await queryHistoryManager.handleCopyRepoList(item, [item]);
expect(executeCommandSpy).not.toBeCalled();
expect(executeCommand).not.toBeCalled();
});
it("should copy repo list for a single variant analysis", async () => {
@@ -840,7 +785,7 @@ describe("QueryHistoryManager", () => {
const item = variantAnalysisHistory[1];
await queryHistoryManager.handleCopyRepoList(item, [item]);
expect(executeCommandSpy).toBeCalledWith(
expect(executeCommand).toBeCalledWith(
"codeQL.copyVariantAnalysisRepoList",
item.variantAnalysis.id,
);
@@ -852,7 +797,7 @@ describe("QueryHistoryManager", () => {
const item1 = variantAnalysisHistory[1];
const item2 = variantAnalysisHistory[3];
await queryHistoryManager.handleCopyRepoList(item1, [item1, item2]);
expect(executeCommandSpy).not.toBeCalled();
expect(executeCommand).not.toBeCalled();
});
});
@@ -1149,6 +1094,7 @@ describe("QueryHistoryManager", () => {
async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) {
const qhm = new QueryHistoryManager(
mockApp,
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

View File

@@ -21,6 +21,7 @@ import { VariantAnalysisManager } from "../../../../src/variant-analysis/variant
import { QueryHistoryManager } from "../../../../src/query-history/query-history-manager";
import { mockedObject } from "../../utils/mocking.helpers";
import { createMockQueryHistoryDirs } from "../../../factories/query-history/query-history-dirs";
import { createMockApp } from "../../../__mocks__/appMock";
// set a higher timeout since recursive delete may take a while, expecially on Windows.
jest.setTimeout(120000);
@@ -73,6 +74,7 @@ describe("Variant Analyses and QueryHistoryManager", () => {
).queries;
qhm = new QueryHistoryManager(
createMockApp({}),
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

View File

@@ -0,0 +1,69 @@
import * as vscode from "vscode";
import { tryOpenExternalFile } from "../../../../../src/vscode-utils/external-files";
import { createMockCommandManager } from "../../../../__mocks__/commandsMock";
import { mockedObject } from "../../../utils/mocking.helpers";
describe("tryOpenExternalFile", () => {
let showTextDocumentSpy: jest.SpiedFunction<
typeof vscode.window.showTextDocument
>;
let showInformationMessageSpy: jest.SpiedFunction<
typeof vscode.window.showInformationMessage
>;
beforeEach(() => {
showTextDocumentSpy = jest
.spyOn(vscode.window, "showTextDocument")
.mockResolvedValue(mockedObject<vscode.TextEditor>({}));
showInformationMessageSpy = jest
.spyOn(vscode.window, "showInformationMessage")
.mockResolvedValue(undefined);
});
it("should open an external file", async () => {
const executeCommand = jest.fn();
const commandManager = createMockCommandManager({ executeCommand });
await tryOpenExternalFile(commandManager, "xxx");
expect(showTextDocumentSpy).toHaveBeenCalledTimes(1);
expect(showTextDocumentSpy).toHaveBeenCalledWith(
vscode.Uri.file("xxx"),
expect.anything(),
);
expect(executeCommand).not.toBeCalled();
});
[
"too large to open",
"Files above 50MB cannot be synchronized with extensions",
].forEach((msg) => {
it(`should fail to open a file because "${msg}" and open externally`, async () => {
const executeCommand = jest.fn();
const commandManager = createMockCommandManager({ executeCommand });
showTextDocumentSpy.mockRejectedValue(new Error(msg));
showInformationMessageSpy.mockResolvedValue({ title: "Yes" });
await tryOpenExternalFile(commandManager, "xxx");
const uri = vscode.Uri.file("xxx");
expect(showTextDocumentSpy).toHaveBeenCalledTimes(1);
expect(showTextDocumentSpy).toHaveBeenCalledWith(uri, expect.anything());
expect(executeCommand).toHaveBeenCalledWith("revealFileInOS", uri);
});
it(`should fail to open a file because "${msg}" and NOT open externally`, async () => {
const executeCommand = jest.fn();
const commandManager = createMockCommandManager({ executeCommand });
showTextDocumentSpy.mockRejectedValue(new Error(msg));
showInformationMessageSpy.mockResolvedValue({ title: "No" });
await tryOpenExternalFile(commandManager, "xxx");
const uri = vscode.Uri.file("xxx");
expect(showTextDocumentSpy).toHaveBeenCalledTimes(1);
expect(showTextDocumentSpy).toHaveBeenCalledWith(uri, expect.anything());
expect(showInformationMessageSpy).toBeCalled();
expect(executeCommand).not.toBeCalled();
});
});
});