diff --git a/extensions/ql-vscode/src/query-history/history-item-label-provider.ts b/extensions/ql-vscode/src/query-history/history-item-label-provider.ts index 98b108560..ced715163 100644 --- a/extensions/ql-vscode/src/query-history/history-item-label-provider.ts +++ b/extensions/ql-vscode/src/query-history/history-item-label-provider.ts @@ -15,7 +15,7 @@ import { humanizeQueryStatus } from "../query-status"; interface InterpolateReplacements { t: string; // Start time q: string; // Query name - d: string; // Database/Controller repo name + d: string; // Database/repositories count r: string; // Result count/Empty s: string; // Status f: string; // Query file name diff --git a/extensions/ql-vscode/test/factories/query-history/variant-analysis-history-item.ts b/extensions/ql-vscode/test/factories/query-history/variant-analysis-history-item.ts index 35f110d6f..7b2789fc2 100644 --- a/extensions/ql-vscode/test/factories/query-history/variant-analysis-history-item.ts +++ b/extensions/ql-vscode/test/factories/query-history/variant-analysis-history-item.ts @@ -1,6 +1,9 @@ import { VariantAnalysisHistoryItem } from "../../../src/query-history/variant-analysis-history-item"; import { QueryStatus } from "../../../src/query-status"; -import { VariantAnalysisStatus } from "../../../src/remote-queries/shared/variant-analysis"; +import { + VariantAnalysis, + VariantAnalysisStatus, +} from "../../../src/remote-queries/shared/variant-analysis"; import { createMockVariantAnalysis } from "../remote-queries/shared/variant-analysis"; export function createMockVariantAnalysisHistoryItem({ @@ -8,8 +11,9 @@ export function createMockVariantAnalysisHistoryItem({ variantAnalysisStatus = VariantAnalysisStatus.Succeeded, failureReason = undefined, resultCount = 0, - userSpecifiedLabel = "query-name", + userSpecifiedLabel = undefined, executionStartTime = undefined, + variantAnalysis = undefined, }: { historyItemStatus?: QueryStatus; variantAnalysisStatus?: VariantAnalysisStatus; @@ -17,6 +21,7 @@ export function createMockVariantAnalysisHistoryItem({ resultCount?: number; userSpecifiedLabel?: string; executionStartTime?: number; + variantAnalysis?: VariantAnalysis; }): VariantAnalysisHistoryItem { return { t: "variant-analysis", @@ -24,10 +29,12 @@ export function createMockVariantAnalysisHistoryItem({ resultCount, status: historyItemStatus, completed: false, - variantAnalysis: createMockVariantAnalysis({ - status: variantAnalysisStatus, - executionStartTime, - }), + variantAnalysis: + variantAnalysis ?? + createMockVariantAnalysis({ + status: variantAnalysisStatus, + executionStartTime, + }), userSpecifiedLabel, }; } diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts index b1f57b714..80e3efe3d 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts @@ -2,12 +2,21 @@ import { env } from "vscode"; import { QueryHistoryConfig } from "../../../../src/config"; import { HistoryItemLabelProvider } from "../../../../src/query-history/history-item-label-provider"; import { createMockLocalQueryInfo } from "../../../factories/query-history/local-query-history-item"; +import { createMockVariantAnalysisHistoryItem } from "../../../factories/query-history/variant-analysis-history-item"; +import { QueryStatus } from "../../../../src/query-status"; +import { + VariantAnalysisRepoStatus, + VariantAnalysisStatus, +} from "../../../../src/remote-queries/shared/variant-analysis"; +import { createMockVariantAnalysis } from "../../../factories/remote-queries/shared/variant-analysis"; +import { createMockScannedRepos } from "../../../factories/remote-queries/shared/scanned-repositories"; describe("HistoryItemLabelProvider", () => { let labelProvider: HistoryItemLabelProvider; let config: QueryHistoryConfig; const date = new Date("2022-01-01T00:00:00.000Z"); const dateStr = date.toLocaleString(env.language); + const executionStartTime = date.getTime(); const userSpecifiedLabel = "user-specified-name"; beforeEach(() => { @@ -82,4 +91,170 @@ describe("HistoryItemLabelProvider", () => { expect(labelProvider.getShortLabel(fqi2)).toBe("query-file.ql"); }); }); + + describe("variant analyses", () => { + it("should interpolate query when user specified", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + userSpecifiedLabel, + executionStartTime, + }); + + expect(labelProvider.getLabel(fqi)).toBe(userSpecifiedLabel); + + fqi.userSpecifiedLabel = "%t %q %d %s %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, + ); + + fqi.userSpecifiedLabel = "%t %q %d %s %%::%t %q %d %s %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories in progress %::${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, + ); + }); + + it("should interpolate query when not user-specified", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + variantAnalysisStatus: VariantAnalysisStatus.Succeeded, + executionStartTime, + resultCount: 16, + }); + + expect(labelProvider.getLabel(fqi)).toBe( + "xxx a-query-name (javascript) xxx", + ); + + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, + ); + + config.format = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %::${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, + ); + }); + + it("should get query short label", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + variantAnalysisStatus: VariantAnalysisStatus.Succeeded, + executionStartTime, + userSpecifiedLabel, + }); + + // fall back on user specified if one exists. + expect(labelProvider.getShortLabel(fqi)).toBe("user-specified-name"); + + // use query name if no user-specified label exists + const fqi2 = createMockVariantAnalysisHistoryItem({}); + + expect(labelProvider.getShortLabel(fqi2)).toBe("a-query-name"); + }); + + describe("when results are present", () => { + it("should display results if there are any", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 16, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path (16 results) %`, + ); + }); + }); + + describe("when results are not present", () => { + it("should skip displaying them", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present in the middle of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present at the start of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = " %t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + ` ${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present at the end of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %% "; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path % `, + ); + }); + }); + }); });