Fold TestManagerBase and related functions into TestManager

This commit is contained in:
Dave Bartolomeo
2024-01-11 11:48:54 -05:00
parent d8968db1b9
commit 2ba23ceead
3 changed files with 93 additions and 114 deletions

View File

@@ -1,35 +0,0 @@
import { extname } from "path";
/**
* Get the full path of the `.expected` file for the specified QL test.
* @param testPath The full path to the test file.
*/
export function getExpectedFile(testPath: string): string {
return getTestOutputFile(testPath, ".expected");
}
/**
* Get the full path of the `.actual` file for the specified QL test.
* @param testPath The full path to the test file.
*/
export function getActualFile(testPath: string): string {
return getTestOutputFile(testPath, ".actual");
}
/**
* Gets the the full path to a particular output file of the specified QL test.
* @param testPath The full path to the QL test.
* @param extension The file extension of the output file.
*/
function getTestOutputFile(testPath: string, extension: string): string {
return changeExtension(testPath, extension);
}
/**
* Change the file extension of the specified path.
* @param p The original file path.
* @param ext The new extension, including the `.`.
*/
function changeExtension(p: string, ext: string): string {
return p.slice(0, -extname(p).length) + ext;
}

View File

@@ -1,74 +0,0 @@
import { copy, createFile, lstat, pathExists } from "fs-extra";
import type { TestUICommands } from "../common/commands";
import { DisposableObject } from "../common/disposable-object";
import { getActualFile, getExpectedFile } from "./test-adapter";
import type { TestItem, TextDocumentShowOptions } from "vscode";
import { Uri, window } from "vscode";
import { basename } from "path";
import type { App } from "../common/app";
type TestNode = TestItem;
/**
* Base class for both the legacy and new test services. Implements commands that are common to
* both.
*/
export abstract class TestManagerBase extends DisposableObject {
protected constructor(private readonly app: App) {
super();
}
public getCommands(): TestUICommands {
return {
"codeQLTests.showOutputDifferences":
this.showOutputDifferences.bind(this),
"codeQLTests.acceptOutput": this.acceptOutput.bind(this),
"codeQLTests.acceptOutputContextTestItem": this.acceptOutput.bind(this),
};
}
/** Override to compute the path of the test file from the selected node. */
protected abstract getTestPath(node: TestNode): string;
private async acceptOutput(node: TestNode): Promise<void> {
const testPath = this.getTestPath(node);
const stat = await lstat(testPath);
if (stat.isFile()) {
const expectedPath = getExpectedFile(testPath);
const actualPath = getActualFile(testPath);
await copy(actualPath, expectedPath, { overwrite: true });
}
}
private async showOutputDifferences(node: TestNode): Promise<void> {
const testId = this.getTestPath(node);
const stat = await lstat(testId);
if (stat.isFile()) {
const expectedPath = getExpectedFile(testId);
const expectedUri = Uri.file(expectedPath);
const actualPath = getActualFile(testId);
const options: TextDocumentShowOptions = {
preserveFocus: true,
preview: true,
};
if (!(await pathExists(expectedPath))) {
// Just create a new file.
await createFile(expectedPath);
}
if (await pathExists(actualPath)) {
const actualUri = Uri.file(actualPath);
await this.app.commands.execute(
"vscode.diff",
expectedUri,
actualUri,
`Expected vs. Actual for ${basename(testId)}`,
options,
);
} else {
await window.showTextDocument(expectedUri, options);
}
}
}
}

View File

@@ -1,10 +1,11 @@
import { readFile } from "fs-extra";
import { copy, createFile, lstat, pathExists, readFile } from "fs-extra";
import type {
CancellationToken,
TestController,
TestItem,
TestRun,
TestRunRequest,
TextDocumentShowOptions,
WorkspaceFolder,
WorkspaceFoldersChangeEvent,
} from "vscode";
@@ -15,6 +16,7 @@ import {
TestRunProfileKind,
Uri,
tests,
window,
workspace,
} from "vscode";
import { DisposableObject } from "../common/disposable-object";
@@ -23,11 +25,46 @@ import type { CodeQLCliServer } from "../codeql-cli/cli";
import { getErrorMessage } from "../common/helpers-pure";
import type { BaseLogger, LogOptions } from "../common/logging";
import type { TestRunner } from "./test-runner";
import { TestManagerBase } from "./test-manager-base";
import type { App } from "../common/app";
import { isWorkspaceFolderOnDisk } from "../common/vscode/workspace-folders";
import type { FileTreeNode } from "../common/file-tree-nodes";
import { FileTreeDirectory, FileTreeLeaf } from "../common/file-tree-nodes";
import type { TestUICommands } from "../common/commands";
import { basename, extname } from "path";
/**
* Get the full path of the `.expected` file for the specified QL test.
* @param testPath The full path to the test file.
*/
function getExpectedFile(testPath: string): string {
return getTestOutputFile(testPath, ".expected");
}
/**
* Get the full path of the `.actual` file for the specified QL test.
* @param testPath The full path to the test file.
*/
function getActualFile(testPath: string): string {
return getTestOutputFile(testPath, ".actual");
}
/**
* Gets the the full path to a particular output file of the specified QL test.
* @param testPath The full path to the QL test.
* @param extension The file extension of the output file.
*/
function getTestOutputFile(testPath: string, extension: string): string {
return changeExtension(testPath, extension);
}
/**
* Change the file extension of the specified path.
* @param p The original file path.
* @param ext The new extension, including the `.`.
*/
function changeExtension(p: string, ext: string): string {
return p.slice(0, -extname(p).length) + ext;
}
/**
* Returns the complete text content of the specified file. If there is an error reading the file,
@@ -108,7 +145,7 @@ class WorkspaceFolderHandler extends DisposableObject {
* Service that populates the VS Code "Test Explorer" panel for CodeQL, and handles running and
* debugging of tests.
*/
export class TestManager extends TestManagerBase {
export class TestManager extends DisposableObject {
/**
* Maps from each workspace folder being tracked to the `WorkspaceFolderHandler` responsible for
* tracking it.
@@ -119,7 +156,7 @@ export class TestManager extends TestManagerBase {
>();
public constructor(
app: App,
private readonly app: App,
private readonly testRunner: TestRunner,
private readonly cliServer: CodeQLCliServer,
// Having this as a parameter with a default value makes passing in a mock easier.
@@ -128,7 +165,7 @@ export class TestManager extends TestManagerBase {
"CodeQL Tests",
),
) {
super(app);
super();
this.testController.createRunProfile(
"Run",
@@ -151,6 +188,15 @@ export class TestManager extends TestManagerBase {
super.dispose();
}
public getCommands(): TestUICommands {
return {
"codeQLTests.showOutputDifferences":
this.showOutputDifferences.bind(this),
"codeQLTests.acceptOutput": this.acceptOutput.bind(this),
"codeQLTests.acceptOutputContextTestItem": this.acceptOutput.bind(this),
};
}
protected getTestPath(node: TestItem): string {
if (node.uri === undefined || node.uri.scheme !== "file") {
throw new Error("Selected test is not a CodeQL test.");
@@ -158,6 +204,48 @@ export class TestManager extends TestManagerBase {
return node.uri.fsPath;
}
private async acceptOutput(node: TestItem): Promise<void> {
const testPath = this.getTestPath(node);
const stat = await lstat(testPath);
if (stat.isFile()) {
const expectedPath = getExpectedFile(testPath);
const actualPath = getActualFile(testPath);
await copy(actualPath, expectedPath, { overwrite: true });
}
}
private async showOutputDifferences(node: TestItem): Promise<void> {
const testId = this.getTestPath(node);
const stat = await lstat(testId);
if (stat.isFile()) {
const expectedPath = getExpectedFile(testId);
const expectedUri = Uri.file(expectedPath);
const actualPath = getActualFile(testId);
const options: TextDocumentShowOptions = {
preserveFocus: true,
preview: true,
};
if (!(await pathExists(expectedPath))) {
// Just create a new file.
await createFile(expectedPath);
}
if (await pathExists(actualPath)) {
const actualUri = Uri.file(actualPath);
await this.app.commands.execute(
"vscode.diff",
expectedUri,
actualUri,
`Expected vs. Actual for ${basename(testId)}`,
options,
);
} else {
await window.showTextDocument(expectedUri, options);
}
}
}
/** Start tracking tests in the specified workspace folders. */
private startTrackingWorkspaceFolders(
workspaceFolders: readonly WorkspaceFolder[],