Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing for saveOnStart PR #2564

Draft
wants to merge 41 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
7a46bac
Save dirty documents before evaluating queries
dbartol Jun 21, 2023
de38b1f
Stop overriding saveBeforeStart for `ql` language
dbartol Jun 21, 2023
1da96c5
Allow `languageId:` scopes in tests
dbartol Jun 21, 2023
b182d7a
Fix PR feedback
dbartol Jun 21, 2023
0bd0bf1
_Correctly_ emulate VS Code's `saveBeforeStart`
dbartol Jun 22, 2023
2397ead
Fix test failure
dbartol Jun 22, 2023
6bdc095
Fix test failure
dbartol Jun 22, 2023
ec71f53
Fix more test failures
dbartol Jun 22, 2023
ff2d67d
Merge remote-tracking branch 'origin/main' into dbartol/save-before-s…
dbartol Jun 22, 2023
3705464
Seriously, I think they'll pass for reals this time.
dbartol Jun 22, 2023
d9a1aa8
Just kidding, _this_ time it's fixed for reals
dbartol Jun 22, 2023
8ff1db1
Fix bad diff
dbartol Jun 28, 2023
d27efb3
Merge remote-tracking branch 'origin/main' into dbartol/save-before-s…
dbartol Jun 29, 2023
adf0ccb
Disable workspace trust for CLI integration tests
dbartol Jun 29, 2023
9fd0697
Fix format
dbartol Jun 29, 2023
dbd257e
More logging
dbartol Jun 29, 2023
bf36051
Increase timeout
dbartol Jun 29, 2023
9f077b0
Run Jest in verbose mode
dbartol Jun 29, 2023
53a51ab
More logging
dbartol Jun 29, 2023
b859bca
Even more logging
dbartol Jun 30, 2023
1f5b391
Dump dirty documents
dbartol Jun 30, 2023
81b2407
Log content of untitled docs
dbartol Jun 30, 2023
c25410e
Log config settings
dbartol Jun 30, 2023
c70ec71
Try different default for saveBeforeStart
dbartol Jun 30, 2023
e80a06c
Try grabbing screenshot
dbartol Jun 30, 2023
6fc0a03
Always upload screenshots
dbartol Jun 30, 2023
eb3c0a2
Set default saveBeforeStart for QL
dbartol Jun 30, 2023
84d40fe
Log active language ID
dbartol Jun 30, 2023
2c69a31
More screenshots
dbartol Jun 30, 2023
53a0778
Back to previous timeout
dbartol Jun 30, 2023
cb3939e
Only create dirty files for commands that don't go through the VS Cod…
dbartol Jul 3, 2023
97715dc
Periodic screenshots
dbartol Jul 7, 2023
f17954f
Better periodic screenshots
dbartol Jul 7, 2023
a22a950
Fix unused
dbartol Jul 7, 2023
b18b3e5
Periodic screenshots step
dbartol Jul 7, 2023
e2e11cc
Screenshots
dbartol Jul 7, 2023
6d9a0e1
Use runner temp directory
dbartol Jul 11, 2023
e5dee84
Screenshots on Windows only
dbartol Jul 11, 2023
800f818
Add explanatory comment
dbartol Jul 11, 2023
6e17fda
Comment about temp directory
dbartol Jul 11, 2023
6b2373d
Delete unneeded files
dbartol Jul 11, 2023
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
Prev Previous commit
Next Next commit
_Correctly_ emulate VS Code's saveBeforeStart
  • Loading branch information
dbartol committed Jun 22, 2023
commit 0bd0bf1944a42181cb3397f1366134d91dc84536
4 changes: 2 additions & 2 deletions extensions/ql-vscode/src/local-queries/local-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,8 @@ export class LocalQueries extends DisposableObject {
range?: Range,
templates?: Record<string, string>,
): Promise<CoreCompletedQuery> {
await saveBeforeStart();

let queryPath: string;
if (queryUri !== undefined) {
// The query URI is provided by the command, most likely because the command was run from an
Expand Down Expand Up @@ -388,8 +390,6 @@ export class LocalQueries extends DisposableObject {
const additionalPacks = getOnDiskWorkspaceFolders();
const extensionPacks = await this.getDefaultExtensionPacks(additionalPacks);

await saveBeforeStart();

const coreQueryRun = this.queryRunner.createQueryRun(
databaseItem.databaseUri.fsPath,
{
Expand Down
55 changes: 8 additions & 47 deletions extensions/ql-vscode/src/run-queries-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ import * as messages from "./pure/messages-shared";
import * as legacyMessages from "./pure/legacy-messages";
import { DatabaseInfo, QueryMetadata } from "./common/interface-types";
import { join, parse, dirname, basename } from "path";
import {
Range,
TextDocument,
TextEditor,
Uri,
window,
workspace,
} from "vscode";
import { Range, TextEditor, Uri, window, workspace } from "vscode";
import { isCanary, VSCODE_SAVE_BEFORE_START_SETTING } from "./config";
import {
pathExists,
Expand Down Expand Up @@ -503,61 +496,29 @@ export async function saveBeforeStart(): Promise<void> {
(VSCODE_SAVE_BEFORE_START_SETTING.getValue<string>() as SaveBeforeStartMode) ??
"nonUntitledEditorsInActiveGroup";

// Despite the names of the modes, the VS Code implementation doesn't restrict itself to the
// current tab group. It saves all dirty files in all groups. We'll do the same.
switch (mode) {
case "nonUntitledEditorsInActiveGroup":
await saveAllInGroup(false);
await workspace.saveAll(false);
break;

case "allEditorsInActiveGroup":
await saveAllInGroup(true);
// The VS Code implementation of this mode only saves an untitled file if it is the document
// in the active editor. That's too much work for us, so we'll just live with the inconsistency.
await workspace.saveAll(true);
break;

case "none":
break;

default:
// Unexpected value. Fall back to the default behavior.
await saveAllInGroup(false);
await workspace.saveAll(false);
break;
}
}

// Used in tests
export async function saveAllInGroup(includeUntitled: boolean): Promise<void> {
// There's no good way to get from a `Tab` to a `TextDocument`, so we'll collect all of the dirty
// documents indexed by their URI, and then compare those URIs against the URIs of the tabs.
const dirtyDocumentUris = new Map<string, TextDocument>();
for (const openDocument of workspace.textDocuments) {
if (openDocument.isDirty) {
console.warn(`${openDocument.uri.toString()} is dirty.`);
if (!openDocument.isUntitled || includeUntitled) {
dirtyDocumentUris.set(openDocument.uri.toString(), openDocument);
}
}
}
if (dirtyDocumentUris.size > 0) {
const tabGroup = window.tabGroups.activeTabGroup;
for (const tab of tabGroup.tabs) {
const input = tab.input;
// The `input` property can be of an arbitrary type, depending on the underlying tab type. For
// text editors (and potentially others), it's an object with a `uri` property. That's all we
// need to know to match it up with a dirty document.
if (typeof input === "object") {
const uri = (input as any).uri;
if (uri instanceof Uri) {
const document = dirtyDocumentUris.get(uri.toString());
if (document !== undefined) {
await document.save();
// Remove the URI from the dirty list so we don't wind up saving the same file twice
// if it's open in multiple editors.
dirtyDocumentUris.delete(uri.toString());
}
}
}
}
}
}

/**
* @param filePath This needs to be equivalent to Java's `Path.toRealPath(NO_FOLLOW_LINKS)`
*/
Expand Down
1 change: 0 additions & 1 deletion extensions/ql-vscode/test/data/debugger/clean.ql

This file was deleted.

20 changes: 20 additions & 0 deletions extensions/ql-vscode/test/data/debugger/codeql-pack.lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
lockVersion: 1.0.0
dependencies:
codeql/javascript-all:
version: 0.6.3
codeql/javascript-queries:
version: 0.6.3
codeql/regex:
version: 0.0.14
codeql/suite-helpers:
version: 0.5.3
codeql/tutorial:
version: 0.0.11
codeql/typos:
version: 0.0.18
codeql/util:
version: 0.0.11
codeql/yaml:
version: 0.0.3
compiled: false
1 change: 0 additions & 1 deletion extensions/ql-vscode/test/data/debugger/dirty.ql

This file was deleted.

1 change: 0 additions & 1 deletion extensions/ql-vscode/test/data/debugger/other-clean.ql

This file was deleted.

1 change: 0 additions & 1 deletion extensions/ql-vscode/test/data/debugger/other-dirty.ql

This file was deleted.

4 changes: 4 additions & 0 deletions extensions/ql-vscode/test/data/debugger/qlpack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: integration-test-debugger-javascript
version: 0.0.0
dependencies:
codeql/javascript-queries: "*"
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { join, resolve } from "path";
import { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
import { getActivatedExtension } from "../../global.helper";
import { tryGetQueryMetadata } from "../../../../src/codeql-cli/query-metadata";
import { getDataFolderFilePath } from "../utils";

describe("tryGetQueryMetadata", () => {
const baseDir = resolve(__dirname, "..");
Expand Down Expand Up @@ -30,7 +31,7 @@ describe("tryGetQueryMetadata", () => {
// Query with empty metadata
const noMetadata = await tryGetQueryMetadata(
cli,
join(baseDir, "data", "simple-query.ql"),
getDataFolderFilePath("debugger/simple-query.ql"),
);

expect(noMetadata).toEqual({});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Selection, Uri, window, workspace } from "vscode";
import { join } from "path";
import {
Position,
Selection,
TextEditor,
Uri,
window,
workspace,
} from "vscode";

Fixed Show fixed Hide fixed
import { DatabaseManager } from "../../../../src/databases/local-databases";
import {
Expand All @@ -13,17 +19,20 @@ import { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
import { QueryOutputDir } from "../../../../src/run-queries-shared";
import { createVSCodeCommandManager } from "../../../../src/common/vscode/commands";
import { AllCommands } from "../../../../src/common/commands";
import { getDataFolderFilePath } from "../utils";

async function selectForQuickEval(
path: string,
line: number,
column: number,
endLine: number,
endColumn: number,
): Promise<void> {
): Promise<TextEditor> {
const document = await workspace.openTextDocument(path);
const editor = await window.showTextDocument(document);
editor.selection = new Selection(line, column, endLine, endColumn);

return editor;
}

async function getResultCount(
Expand All @@ -42,9 +51,11 @@ describeWithCodeQL()("Debugger", () => {
let databaseManager: DatabaseManager;
let cli: CodeQLCliServer;
const appCommands = createVSCodeCommandManager<AllCommands>();
const simpleQueryPath = join(__dirname, "..", "data", "simple-query.ql");
const quickEvalQueryPath = join(__dirname, "..", "data", "QuickEvalQuery.ql");
const quickEvalLibPath = join(__dirname, "..", "data", "QuickEvalLib.qll");
const simpleQueryPath = getDataFolderFilePath("debugger/simple-query.ql");
const quickEvalQueryPath = getDataFolderFilePath(
"debugger/QuickEvalQuery.ql",
);
const quickEvalLibPath = getDataFolderFilePath("debugger/QuickEvalLib.qll");

beforeEach(async () => {
const extension = await getActivatedExtension();
Expand Down Expand Up @@ -138,4 +149,35 @@ describeWithCodeQL()("Debugger", () => {
await controller.expectStopped();
});
});

it("should save dirty documents before launching a debug session", async () => {
await withDebugController(appCommands, async (controller) => {
const editor = await selectForQuickEval(quickEvalLibPath, 4, 15, 4, 32);
await editor.edit((editBuilder) => {
editBuilder.insert(new Position(0, 0), "/* comment */");
});
expect(editor.document.isDirty).toBe(true);

await controller.startDebuggingSelection({
query: quickEvalQueryPath, // The query context. This query extends the abstract class.
});
await controller.expectLaunched();

// Should have saved the dirty document.
expect(editor.document.isDirty).toBe(false);

await controller.expectSucceeded();
await controller.expectStopped();

await editor.edit((editBuilder) => {
editBuilder.insert(new Position(0, 0), "/* another comment */");
});
expect(editor.document.isDirty).toBe(true);

await controller.continueDebuggingSelection();
await controller.expectSucceeded();
await controller.expectStopped();
expect(editor.document.isDirty).toBe(false);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
const path = require("path");
const fs = require("fs");

const {
config: baseConfig,
tmpDir,
rootDir,
} = require("../jest-runner-vscode.config.base");

const tmpDataDir = path.join(tmpDir.name, "data");
fs.cpSync(path.resolve(rootDir, "test/data"), tmpDataDir, {
recursive: true,
});

/** @type import("jest-runner-vscode").RunnerOptions */
const config = {
...baseConfig,
Expand All @@ -17,7 +24,7 @@ const config = {
"github.codespaces",
"--disable-extension",
"github.copilot",
path.resolve(rootDir, "test/data"),
tmpDataDir,
path.resolve(rootDir, "test/data-extensions"), // folder containing the extension packs and packs that are targeted by the extension pack
// CLI integration tests requires a multi-root workspace so that the data and the QL sources are accessible.
...(process.env.TEST_CODEQL_PATH ? [process.env.TEST_CODEQL_PATH] : []),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ import {
} from "../../../src/common/commands";
import { ProgressCallback } from "../../../src/common/vscode/progress";
import { withDebugController } from "./debugger/debug-controller";
import { getDataFolderFilePath } from "./utils";

const simpleQueryPath = getDataFolderFilePath("debugger/simple-query.ql");

type DebugMode = "localQueries" | "debug";

Expand Down Expand Up @@ -213,13 +216,12 @@ describeWithCodeQL()("Queries", () => {

describe.each(MODES)("running queries (%s)", (mode) => {
it("should run a query", async () => {
const queryPath = join(__dirname, "data", "simple-query.ql");
const result = await compileAndRunQuery(
mode,
appCommandManager,
localQueries,
QuickEvalType.None,
Uri.file(queryPath),
Uri.file(simpleQueryPath),
progress,
token,
dbItem,
Expand All @@ -233,13 +235,12 @@ describeWithCodeQL()("Queries", () => {
// Asserts a fix for bug https://github.com/github/vscode-codeql/issues/733
it("should restart the database and run a query", async () => {
await appCommandManager.execute("codeQL.restartQueryServer");
const queryPath = join(__dirname, "data", "simple-query.ql");
const result = await compileAndRunQuery(
mode,
appCommandManager,
localQueries,
QuickEvalType.None,
Uri.file(queryPath),
Uri.file(simpleQueryPath),
progress,
token,
dbItem,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { workspace } from "vscode";
import { join } from "path";

/**
* Get the absolute path to a file in the temporary copy of the `data` folder.
*/
export function getDataFolderFilePath(path: string): string {
return join(workspace.workspaceFolders![0].uri.fsPath, path);
}
Loading
Loading