Migrate minimal-workspace integration tests to Jest (#1786)
This commit is contained in:
@@ -9,5 +9,6 @@ module.exports = {
|
||||
"<rootDir>/src/view",
|
||||
"<rootDir>/test",
|
||||
"<rootDir>/out/vscode-tests/no-workspace",
|
||||
"<rootDir>/out/vscode-tests/minimal-workspace",
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
"test:view": "jest --projects src/view",
|
||||
"integration": "npm-run-all integration:*",
|
||||
"integration:no-workspace": "jest --projects out/vscode-tests/no-workspace",
|
||||
"integration:minimal-workspace": "node ./out/vscode-tests/run-integration-tests.js minimal-workspace",
|
||||
"integration:minimal-workspace": "jest --projects out/vscode-tests/minimal-workspace",
|
||||
"cli-integration": "node ./out/vscode-tests/run-integration-tests.js cli-integration",
|
||||
"update-vscode": "node ./node_modules/vscode/bin/install",
|
||||
"format": "prettier --write **/*.{ts,tsx} && eslint . --ext .ts,.tsx --fix",
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
import * as assert from "assert";
|
||||
import * as path from "path";
|
||||
import * as vscode from "vscode";
|
||||
import * as determiningSelectedQueryTest from "./determining-selected-query-test";
|
||||
|
||||
describe("launching with a minimal workspace", async () => {
|
||||
// Temporary until Mocha is fully removed. This is necessary for passing timeouts to `it`.
|
||||
declare let it: jest.It;
|
||||
|
||||
describe("launching with a minimal workspace", () => {
|
||||
const ext = vscode.extensions.getExtension("GitHub.vscode-codeql");
|
||||
it("should install the extension", () => {
|
||||
assert(ext);
|
||||
expect(ext).toBeDefined();
|
||||
});
|
||||
|
||||
// Note, this test will only pass in pristine workspaces. This means that when run locally and you
|
||||
// reuse an existing workspace that starts with an open ql file, this test will fail. There is
|
||||
// no need to make any changes since this will still pass on CI.
|
||||
it("should not activate the extension at first", () => {
|
||||
assert(ext!.isActive === false);
|
||||
expect(ext!.isActive).toEqual(false);
|
||||
});
|
||||
|
||||
it("should activate the extension when a .ql file is opened", async function () {
|
||||
this.timeout(60000);
|
||||
it("should activate the extension when a .ql file is opened", async () => {
|
||||
await delay();
|
||||
|
||||
const folders = vscode.workspace.workspaceFolders;
|
||||
assert(folders && folders.length === 1);
|
||||
expect(folders?.length).toEqual(1);
|
||||
const folderPath = folders![0].uri.fsPath;
|
||||
const documentPath = path.resolve(folderPath, "query.ql");
|
||||
const document = await vscode.workspace.openTextDocument(documentPath);
|
||||
assert(document.languageId === "ql");
|
||||
expect(document.languageId).toEqual("ql");
|
||||
// Delay slightly so that the extension has time to activate.
|
||||
await delay();
|
||||
assert(ext!.isActive);
|
||||
});
|
||||
expect(ext!.isActive).toBeTruthy();
|
||||
}, 60_000);
|
||||
|
||||
async function delay() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 4000));
|
||||
|
||||
@@ -1,28 +1,15 @@
|
||||
import * as Sinon from "sinon";
|
||||
import { expect } from "chai";
|
||||
import { workspace } from "vscode";
|
||||
|
||||
import {
|
||||
CliConfigListener,
|
||||
ConfigListener,
|
||||
QueryHistoryConfigListener,
|
||||
QueryServerConfigListener,
|
||||
} from "../../config";
|
||||
|
||||
describe("config listeners", function () {
|
||||
// Because we are adding some extra waiting, need to bump the test timeouts.
|
||||
this.timeout(5000);
|
||||
|
||||
let sandbox: Sinon.SinonSandbox;
|
||||
beforeEach(() => {
|
||||
sandbox = Sinon.createSandbox();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe("config listeners", () => {
|
||||
interface TestConfig<T> {
|
||||
clazz: new () => unknown;
|
||||
clazz: new () => ConfigListener;
|
||||
settings: {
|
||||
name: string;
|
||||
property: string;
|
||||
@@ -95,23 +82,14 @@ describe("config listeners", function () {
|
||||
|
||||
testConfig.forEach((config) => {
|
||||
describe(config.clazz.name, () => {
|
||||
let listener: any;
|
||||
let spy: Sinon.SinonSpy;
|
||||
beforeEach(() => {
|
||||
listener = new config.clazz();
|
||||
spy = Sinon.spy();
|
||||
listener.onDidChangeConfiguration(spy);
|
||||
});
|
||||
|
||||
config.settings.forEach((setting) => {
|
||||
let origValue: any;
|
||||
let origValue: string | number | boolean | undefined;
|
||||
beforeEach(async () => {
|
||||
origValue = workspace.getConfiguration().get(setting.name);
|
||||
await workspace
|
||||
.getConfiguration()
|
||||
.update(setting.name, setting.values[0]);
|
||||
await wait();
|
||||
spy.resetHistory();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -120,12 +98,17 @@ describe("config listeners", function () {
|
||||
});
|
||||
|
||||
it(`should listen for changes to '${setting.name}'`, async () => {
|
||||
const listener = new config.clazz();
|
||||
const onDidChangeConfiguration = jest.fn();
|
||||
listener.onDidChangeConfiguration(onDidChangeConfiguration);
|
||||
|
||||
await workspace
|
||||
.getConfiguration()
|
||||
.update(setting.name, setting.values[1]);
|
||||
await wait();
|
||||
expect(listener[setting.property]).to.eq(setting.values[1]);
|
||||
expect(spy).to.have.been.calledOnce;
|
||||
const newValue = listener[setting.property as keyof typeof listener];
|
||||
expect(newValue).toEqual(setting.values[1]);
|
||||
expect(onDidChangeConfiguration).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import * as sinon from "sinon";
|
||||
import * as tmp from "tmp";
|
||||
import * as fs from "fs-extra";
|
||||
import * as path from "path";
|
||||
import { expect } from "chai";
|
||||
import { CancellationToken, ExtensionContext, Uri, workspace } from "vscode";
|
||||
|
||||
import {
|
||||
@@ -15,7 +13,7 @@ import {
|
||||
} from "../../databases";
|
||||
import { Logger } from "../../logging";
|
||||
import { ProgressCallback } from "../../commandRunner";
|
||||
import { CodeQLCliServer } from "../../cli";
|
||||
import { CodeQLCliServer, DbInfo } from "../../cli";
|
||||
import {
|
||||
encodeArchiveBasePath,
|
||||
encodeSourceArchiveUri,
|
||||
@@ -31,37 +29,29 @@ describe("databases", () => {
|
||||
};
|
||||
|
||||
let databaseManager: DatabaseManager;
|
||||
let updateSpy: sinon.SinonSpy;
|
||||
let getSpy: sinon.SinonStub;
|
||||
let dbChangedHandler: sinon.SinonSpy;
|
||||
let registerSpy: sinon.SinonSpy;
|
||||
let deregisterSpy: sinon.SinonSpy;
|
||||
let supportsDatabaseRegistrationSpy: sinon.SinonStub;
|
||||
let supportsLanguageNameSpy: sinon.SinonStub;
|
||||
let resolveDatabaseSpy: sinon.SinonStub;
|
||||
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
let updateSpy: jest.Mock<Promise<void>, []>;
|
||||
let registerSpy: jest.Mock<Promise<void>, []>;
|
||||
let deregisterSpy: jest.Mock<Promise<void>, []>;
|
||||
let supportsLanguageNameSpy: jest.Mock<Promise<boolean>, []>;
|
||||
let resolveDatabaseSpy: jest.Mock<Promise<DbInfo>, []>;
|
||||
|
||||
let dir: tmp.DirResult;
|
||||
|
||||
beforeEach(() => {
|
||||
dir = tmp.dirSync();
|
||||
|
||||
sandbox = sinon.createSandbox();
|
||||
updateSpy = sandbox.spy();
|
||||
getSpy = sandbox.stub();
|
||||
getSpy.returns([]);
|
||||
registerSpy = sandbox.stub();
|
||||
deregisterSpy = sandbox.stub();
|
||||
dbChangedHandler = sandbox.spy();
|
||||
supportsDatabaseRegistrationSpy = sandbox.stub();
|
||||
supportsDatabaseRegistrationSpy.resolves(true);
|
||||
supportsLanguageNameSpy = sandbox.stub();
|
||||
resolveDatabaseSpy = sandbox.stub();
|
||||
updateSpy = jest.fn(() => Promise.resolve(undefined));
|
||||
registerSpy = jest.fn(() => Promise.resolve(undefined));
|
||||
deregisterSpy = jest.fn(() => Promise.resolve(undefined));
|
||||
supportsLanguageNameSpy = jest.fn(() => Promise.resolve(true));
|
||||
resolveDatabaseSpy = jest.fn(() => Promise.resolve({} as DbInfo));
|
||||
|
||||
databaseManager = new DatabaseManager(
|
||||
{
|
||||
workspaceState: {
|
||||
update: updateSpy,
|
||||
get: getSpy,
|
||||
get: () => [],
|
||||
},
|
||||
// pretend like databases added in the temp dir are controlled by the extension
|
||||
// so that they are deleted upon removal
|
||||
@@ -77,7 +67,7 @@ describe("databases", () => {
|
||||
{
|
||||
cliConstraints: {
|
||||
supportsLanguageName: supportsLanguageNameSpy,
|
||||
supportsDatabaseRegistration: supportsDatabaseRegistrationSpy,
|
||||
supportsDatabaseRegistration: () => true,
|
||||
},
|
||||
resolveDatabase: resolveDatabaseSpy,
|
||||
} as unknown as CodeQLCliServer,
|
||||
@@ -91,39 +81,38 @@ describe("databases", () => {
|
||||
// Unfortunately, during a test it is not possible to convert from
|
||||
// a single root workspace to multi-root, so must stub out relevant
|
||||
// functions
|
||||
sandbox.stub(workspace, "updateWorkspaceFolders");
|
||||
sandbox.spy(workspace, "onDidChangeWorkspaceFolders");
|
||||
jest.spyOn(workspace, "updateWorkspaceFolders").mockReturnValue(true);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
dir.removeCallback();
|
||||
databaseManager.dispose(testDisposeHandler);
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it("should fire events when adding and removing a db item", async () => {
|
||||
const mockDbItem = createMockDB();
|
||||
const spy = sinon.spy();
|
||||
databaseManager.onDidChangeDatabaseItem(spy);
|
||||
const onDidChangeDatabaseItem = jest.fn();
|
||||
databaseManager.onDidChangeDatabaseItem(onDidChangeDatabaseItem);
|
||||
await (databaseManager as any).addDatabaseItem(
|
||||
{} as ProgressCallback,
|
||||
{} as CancellationToken,
|
||||
mockDbItem,
|
||||
);
|
||||
|
||||
expect((databaseManager as any)._databaseItems).to.deep.eq([mockDbItem]);
|
||||
expect(updateSpy).to.have.been.calledWith("databaseList", [
|
||||
expect((databaseManager as any)._databaseItems).toEqual([mockDbItem]);
|
||||
expect(updateSpy).toBeCalledWith("databaseList", [
|
||||
{
|
||||
options: MOCK_DB_OPTIONS,
|
||||
uri: dbLocationUri().toString(true),
|
||||
},
|
||||
]);
|
||||
expect(spy).to.have.been.calledWith({
|
||||
expect(onDidChangeDatabaseItem).toBeCalledWith({
|
||||
item: undefined,
|
||||
kind: DatabaseEventKind.Add,
|
||||
});
|
||||
|
||||
sinon.reset();
|
||||
updateSpy.mockClear();
|
||||
onDidChangeDatabaseItem.mockClear();
|
||||
|
||||
// now remove the item
|
||||
await databaseManager.removeDatabaseItem(
|
||||
@@ -131,9 +120,9 @@ describe("databases", () => {
|
||||
{} as CancellationToken,
|
||||
mockDbItem,
|
||||
);
|
||||
expect((databaseManager as any)._databaseItems).to.deep.eq([]);
|
||||
expect(updateSpy).to.have.been.calledWith("databaseList", []);
|
||||
expect(spy).to.have.been.calledWith({
|
||||
expect((databaseManager as any)._databaseItems).toEqual([]);
|
||||
expect(updateSpy).toBeCalledWith("databaseList", []);
|
||||
expect(onDidChangeDatabaseItem).toBeCalledWith({
|
||||
item: undefined,
|
||||
kind: DatabaseEventKind.Remove,
|
||||
});
|
||||
@@ -141,27 +130,25 @@ describe("databases", () => {
|
||||
|
||||
it("should rename a db item and emit an event", async () => {
|
||||
const mockDbItem = createMockDB();
|
||||
const spy = sinon.spy();
|
||||
databaseManager.onDidChangeDatabaseItem(spy);
|
||||
const onDidChangeDatabaseItem = jest.fn();
|
||||
databaseManager.onDidChangeDatabaseItem(onDidChangeDatabaseItem);
|
||||
await (databaseManager as any).addDatabaseItem(
|
||||
{} as ProgressCallback,
|
||||
{} as CancellationToken,
|
||||
mockDbItem,
|
||||
);
|
||||
|
||||
sinon.restore();
|
||||
|
||||
await databaseManager.renameDatabaseItem(mockDbItem, "new name");
|
||||
|
||||
expect(mockDbItem.name).to.eq("new name");
|
||||
expect(updateSpy).to.have.been.calledWith("databaseList", [
|
||||
expect(mockDbItem.name).toBe("new name");
|
||||
expect(updateSpy).toBeCalledWith("databaseList", [
|
||||
{
|
||||
options: { ...MOCK_DB_OPTIONS, displayName: "new name" },
|
||||
uri: dbLocationUri().toString(true),
|
||||
},
|
||||
]);
|
||||
|
||||
expect(spy).to.have.been.calledWith({
|
||||
expect(onDidChangeDatabaseItem).toBeCalledWith({
|
||||
item: undefined,
|
||||
kind: DatabaseEventKind.Rename,
|
||||
});
|
||||
@@ -169,8 +156,8 @@ describe("databases", () => {
|
||||
|
||||
describe("add / remove database items", () => {
|
||||
it("should add a database item", async () => {
|
||||
const spy = sandbox.spy();
|
||||
databaseManager.onDidChangeDatabaseItem(spy);
|
||||
const onDidChangeDatabaseItem = jest.fn();
|
||||
databaseManager.onDidChangeDatabaseItem(onDidChangeDatabaseItem);
|
||||
const mockDbItem = createMockDB();
|
||||
|
||||
await (databaseManager as any).addDatabaseItem(
|
||||
@@ -179,8 +166,8 @@ describe("databases", () => {
|
||||
mockDbItem,
|
||||
);
|
||||
|
||||
expect(databaseManager.databaseItems).to.deep.eq([mockDbItem]);
|
||||
expect(updateSpy).to.have.been.calledWith("databaseList", [
|
||||
expect(databaseManager.databaseItems).toEqual([mockDbItem]);
|
||||
expect(updateSpy).toBeCalledWith("databaseList", [
|
||||
{
|
||||
uri: dbLocationUri().toString(true),
|
||||
options: MOCK_DB_OPTIONS,
|
||||
@@ -191,35 +178,36 @@ describe("databases", () => {
|
||||
item: undefined,
|
||||
kind: DatabaseEventKind.Add,
|
||||
};
|
||||
expect(spy).to.have.been.calledWith(mockEvent);
|
||||
expect(onDidChangeDatabaseItem).toBeCalledWith(mockEvent);
|
||||
});
|
||||
|
||||
it("should add a database item source archive", async function () {
|
||||
it("should add a database item source archive", async () => {
|
||||
const mockDbItem = createMockDB();
|
||||
mockDbItem.name = "xxx";
|
||||
await (databaseManager as any).addDatabaseSourceArchiveFolder(mockDbItem);
|
||||
await databaseManager.addDatabaseSourceArchiveFolder(mockDbItem);
|
||||
|
||||
// workspace folders should be updated. We can only check the mocks since
|
||||
// when running as a test, we are not allowed to update the workspace folders
|
||||
expect(workspace.updateWorkspaceFolders).to.have.been.calledWith(1, 0, {
|
||||
expect(workspace.updateWorkspaceFolders).toHaveBeenCalledWith(1, 0, {
|
||||
name: "[xxx source archive]",
|
||||
// must use a matcher here since vscode URIs with the same path
|
||||
// are not always equal due to internal state.
|
||||
uri: sinon.match.has(
|
||||
"fsPath",
|
||||
encodeArchiveBasePath(sourceLocationUri().fsPath).fsPath,
|
||||
),
|
||||
uri: expect.objectContaining({
|
||||
fsPath: encodeArchiveBasePath(sourceLocationUri().fsPath).fsPath,
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("should remove a database item", async () => {
|
||||
const mockDbItem = createMockDB();
|
||||
sandbox.stub(fs, "remove").resolves();
|
||||
const removeMock = jest
|
||||
.spyOn(fs, "remove")
|
||||
.mockImplementation(() => Promise.resolve());
|
||||
|
||||
// pretend that this item is the first workspace folder in the list
|
||||
sandbox
|
||||
.stub(mockDbItem, "belongsToSourceArchiveExplorerUri")
|
||||
.returns(true);
|
||||
jest
|
||||
.spyOn(mockDbItem, "belongsToSourceArchiveExplorerUri")
|
||||
.mockReturnValue(true);
|
||||
|
||||
await (databaseManager as any).addDatabaseItem(
|
||||
{} as ProgressCallback,
|
||||
@@ -227,7 +215,7 @@ describe("databases", () => {
|
||||
mockDbItem,
|
||||
);
|
||||
|
||||
updateSpy.resetHistory();
|
||||
updateSpy.mockClear();
|
||||
|
||||
await databaseManager.removeDatabaseItem(
|
||||
{} as ProgressCallback,
|
||||
@@ -235,30 +223,30 @@ describe("databases", () => {
|
||||
mockDbItem,
|
||||
);
|
||||
|
||||
expect(databaseManager.databaseItems).to.deep.eq([]);
|
||||
expect(updateSpy).to.have.been.calledWith("databaseList", []);
|
||||
expect(databaseManager.databaseItems).toEqual([]);
|
||||
expect(updateSpy).toBeCalledWith("databaseList", []);
|
||||
// should remove the folder
|
||||
expect(workspace.updateWorkspaceFolders).to.have.been.calledWith(0, 1);
|
||||
expect(workspace.updateWorkspaceFolders).toBeCalledWith(0, 1);
|
||||
|
||||
// should also delete the db contents
|
||||
expect(fs.remove).to.have.been.calledWith(mockDbItem.databaseUri.fsPath);
|
||||
expect(removeMock).toBeCalledWith(mockDbItem.databaseUri.fsPath);
|
||||
});
|
||||
|
||||
it("should remove a database item outside of the extension controlled area", async () => {
|
||||
const mockDbItem = createMockDB();
|
||||
sandbox.stub(fs, "remove").resolves();
|
||||
const removeMock = jest.spyOn(fs, "remove");
|
||||
removeMock.mockReset().mockImplementation(() => Promise.resolve());
|
||||
|
||||
// pretend that this item is the first workspace folder in the list
|
||||
sandbox
|
||||
.stub(mockDbItem, "belongsToSourceArchiveExplorerUri")
|
||||
.returns(true);
|
||||
|
||||
jest
|
||||
.spyOn(mockDbItem, "belongsToSourceArchiveExplorerUri")
|
||||
.mockReturnValue(true);
|
||||
await (databaseManager as any).addDatabaseItem(
|
||||
{} as ProgressCallback,
|
||||
{} as CancellationToken,
|
||||
mockDbItem,
|
||||
);
|
||||
updateSpy.resetHistory();
|
||||
updateSpy.mockClear();
|
||||
|
||||
// pretend that the database location is not controlled by the extension
|
||||
(databaseManager as any).ctx.storagePath = "hucairz";
|
||||
@@ -269,13 +257,13 @@ describe("databases", () => {
|
||||
mockDbItem,
|
||||
);
|
||||
|
||||
expect(databaseManager.databaseItems).to.deep.eq([]);
|
||||
expect(updateSpy).to.have.been.calledWith("databaseList", []);
|
||||
expect(databaseManager.databaseItems).toEqual([]);
|
||||
expect(updateSpy).toBeCalledWith("databaseList", []);
|
||||
// should remove the folder
|
||||
expect(workspace.updateWorkspaceFolders).to.have.been.calledWith(0, 1);
|
||||
expect(workspace.updateWorkspaceFolders).toBeCalledWith(0, 1);
|
||||
|
||||
// should NOT delete the db contents
|
||||
expect(fs.remove).not.to.have.been.called;
|
||||
expect(removeMock).not.toBeCalled();
|
||||
});
|
||||
|
||||
it("should register and deregister a database when adding and removing it", async () => {
|
||||
@@ -283,7 +271,7 @@ describe("databases", () => {
|
||||
// registration messages.
|
||||
const mockDbItem = createMockDB();
|
||||
|
||||
sandbox.stub(fs, "remove").resolves();
|
||||
jest.spyOn(fs, "remove").mockImplementation(() => Promise.resolve());
|
||||
|
||||
await (databaseManager as any).addDatabaseItem(
|
||||
{} as ProgressCallback,
|
||||
@@ -291,7 +279,7 @@ describe("databases", () => {
|
||||
mockDbItem,
|
||||
);
|
||||
// Should have registered this database
|
||||
expect(registerSpy).to.have.been.calledWith({}, {}, mockDbItem);
|
||||
expect(registerSpy).toBeCalledWith({}, {}, mockDbItem);
|
||||
|
||||
await databaseManager.removeDatabaseItem(
|
||||
{} as ProgressCallback,
|
||||
@@ -300,7 +288,7 @@ describe("databases", () => {
|
||||
);
|
||||
|
||||
// Should have deregistered this database
|
||||
expect(deregisterSpy).to.have.been.calledWith({}, {}, mockDbItem);
|
||||
expect(deregisterSpy).toBeCalledWith({}, {}, mockDbItem);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -308,13 +296,15 @@ describe("databases", () => {
|
||||
it("should fail to resolve when not a uri", () => {
|
||||
const db = createMockDB(Uri.parse("file:/sourceArchive-uri/"));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
expect(() => db.resolveSourceFile("abc")).to.throw("Scheme is missing");
|
||||
expect(() => db.resolveSourceFile("abc")).toThrowError(
|
||||
"Scheme is missing",
|
||||
);
|
||||
});
|
||||
|
||||
it("should fail to resolve when not a file uri", () => {
|
||||
const db = createMockDB(Uri.parse("file:/sourceArchive-uri/"));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
expect(() => db.resolveSourceFile("http://abc")).to.throw(
|
||||
expect(() => db.resolveSourceFile("http://abc")).toThrowError(
|
||||
"Invalid uri scheme",
|
||||
);
|
||||
});
|
||||
@@ -324,14 +314,14 @@ describe("databases", () => {
|
||||
const db = createMockDB(Uri.parse("file:/sourceArchive-uri/"));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
const resolved = db.resolveSourceFile(undefined);
|
||||
expect(resolved.toString(true)).to.eq(dbLocationUri().toString(true));
|
||||
expect(resolved.toString(true)).toBe(dbLocationUri().toString(true));
|
||||
});
|
||||
|
||||
it("should resolve an empty file", () => {
|
||||
const db = createMockDB(Uri.parse("file:/sourceArchive-uri/"));
|
||||
(db as any)._contents.sourceArchiveUri = undefined;
|
||||
const resolved = db.resolveSourceFile("file:");
|
||||
expect(resolved.toString()).to.eq("file:///");
|
||||
expect(resolved.toString()).toBe("file:///");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -347,7 +337,7 @@ describe("databases", () => {
|
||||
|
||||
// must recreate an encoded archive uri instead of typing out the
|
||||
// text since the uris will be different on windows and ubuntu.
|
||||
expect(resolved.toString()).to.eq(
|
||||
expect(resolved.toString()).toBe(
|
||||
encodeSourceArchiveUri({
|
||||
sourceArchiveZipPath: "sourceArchive-uri",
|
||||
pathWithinSourceArchive: "def/abc",
|
||||
@@ -366,7 +356,7 @@ describe("databases", () => {
|
||||
|
||||
// must recreate an encoded archive uri instead of typing out the
|
||||
// text since the uris will be different on windows and ubuntu.
|
||||
expect(resolved.toString()).to.eq(
|
||||
expect(resolved.toString()).toBe(
|
||||
encodeSourceArchiveUri({
|
||||
sourceArchiveZipPath: "sourceArchive-uri",
|
||||
pathWithinSourceArchive: "def/abc",
|
||||
@@ -382,7 +372,7 @@ describe("databases", () => {
|
||||
}),
|
||||
);
|
||||
const resolved = db.resolveSourceFile("file:");
|
||||
expect(resolved.toString()).to.eq(
|
||||
expect(resolved.toString()).toBe(
|
||||
"codeql-zip-archive://1-18/sourceArchive-uri/def/",
|
||||
);
|
||||
});
|
||||
@@ -391,145 +381,145 @@ describe("databases", () => {
|
||||
it("should handle an empty file", () => {
|
||||
const db = createMockDB(Uri.parse("file:/sourceArchive-uri/"));
|
||||
const resolved = db.resolveSourceFile("");
|
||||
expect(resolved.toString()).to.eq("file:///sourceArchive-uri/");
|
||||
expect(resolved.toString()).toBe("file:///sourceArchive-uri/");
|
||||
});
|
||||
});
|
||||
|
||||
it("should not support the primary language", async () => {
|
||||
supportsLanguageNameSpy.resolves(false);
|
||||
supportsLanguageNameSpy.mockResolvedValue(false);
|
||||
|
||||
const result = await (databaseManager as any).getPrimaryLanguage("hucairz");
|
||||
expect(result).to.be.undefined;
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should get the primary language", async () => {
|
||||
supportsLanguageNameSpy.resolves(true);
|
||||
resolveDatabaseSpy.resolves({
|
||||
supportsLanguageNameSpy.mockResolvedValue(true);
|
||||
resolveDatabaseSpy.mockResolvedValue({
|
||||
languages: ["python"],
|
||||
});
|
||||
} as unknown as DbInfo);
|
||||
const result = await (databaseManager as any).getPrimaryLanguage("hucairz");
|
||||
expect(result).to.eq("python");
|
||||
expect(result).toBe("python");
|
||||
});
|
||||
|
||||
it("should handle missing the primary language", async () => {
|
||||
supportsLanguageNameSpy.resolves(true);
|
||||
resolveDatabaseSpy.resolves({
|
||||
supportsLanguageNameSpy.mockResolvedValue(true);
|
||||
resolveDatabaseSpy.mockResolvedValue({
|
||||
languages: [],
|
||||
});
|
||||
} as unknown as DbInfo);
|
||||
const result = await (databaseManager as any).getPrimaryLanguage("hucairz");
|
||||
expect(result).to.eq("");
|
||||
expect(result).toBe("");
|
||||
});
|
||||
|
||||
describe("isAffectedByTest", () => {
|
||||
const directoryStats = new fs.Stats();
|
||||
const fileStats = new fs.Stats();
|
||||
|
||||
before(() => {
|
||||
sinon.stub(directoryStats, "isDirectory").returns(true);
|
||||
sinon.stub(fileStats, "isDirectory").returns(false);
|
||||
beforeEach(() => {
|
||||
jest.spyOn(directoryStats, "isDirectory").mockReturnValue(true);
|
||||
jest.spyOn(fileStats, "isDirectory").mockReturnValue(false);
|
||||
});
|
||||
|
||||
it("should return true for testproj database in test directory", async () => {
|
||||
sandbox.stub(fs, "stat").resolves(directoryStats);
|
||||
jest.spyOn(fs, "stat").mockResolvedValue(directoryStats);
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.testproj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).to.true;
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for non-existent test directory", async () => {
|
||||
sandbox.stub(fs, "stat").throws("Simulated Error: ENOENT");
|
||||
jest.spyOn(fs, "stat").mockImplementation(() => {
|
||||
throw new Error("Simulated Error: ENOENT");
|
||||
});
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.testproj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).to.false;
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for non-testproj database in test directory", async () => {
|
||||
sandbox.stub(fs, "stat").resolves(directoryStats);
|
||||
jest.spyOn(fs, "stat").mockResolvedValue(directoryStats);
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.proj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).to.false;
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for testproj database outside test directory", async () => {
|
||||
sandbox.stub(fs, "stat").resolves(directoryStats);
|
||||
jest.spyOn(fs, "stat").mockResolvedValue(directoryStats);
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/other/dir.testproj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).to.false;
|
||||
expect(await db.isAffectedByTest("/path/to/dir")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for testproj database for prefix directory", async () => {
|
||||
sandbox.stub(fs, "stat").resolves(directoryStats);
|
||||
jest.spyOn(fs, "stat").mockResolvedValue(directoryStats);
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.testproj"),
|
||||
);
|
||||
// /path/to/d is a prefix of /path/to/dir/dir.testproj, but
|
||||
// /path/to/dir/dir.testproj is not under /path/to/d
|
||||
expect(await db.isAffectedByTest("/path/to/d")).to.false;
|
||||
expect(await db.isAffectedByTest("/path/to/d")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for testproj database for test file", async () => {
|
||||
sandbox.stub(fs, "stat").resolves(fileStats);
|
||||
jest.spyOn(fs, "stat").mockResolvedValue(fileStats);
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.testproj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/dir/test.ql")).to.true;
|
||||
expect(await db.isAffectedByTest("/path/to/dir/test.ql")).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for non-existent test file", async () => {
|
||||
sandbox.stub(fs, "stat").throws("Simulated Error: ENOENT");
|
||||
jest.spyOn(fs, "stat").mockImplementation(() => {
|
||||
throw new Error("Simulated Error: ENOENT");
|
||||
});
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.testproj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/dir/test.ql")).to.false;
|
||||
expect(await db.isAffectedByTest("/path/to/dir/test.ql")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for non-testproj database for test file", async () => {
|
||||
sandbox.stub(fs, "stat").resolves(fileStats);
|
||||
jest.spyOn(fs, "stat").mockResolvedValue(fileStats);
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.proj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/dir/test.ql")).to.false;
|
||||
expect(await db.isAffectedByTest("/path/to/dir/test.ql")).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for testproj database not matching test file", async () => {
|
||||
sandbox.stub(fs, "stat").resolves(fileStats);
|
||||
jest.spyOn(fs, "stat").mockResolvedValue(fileStats);
|
||||
const db = createMockDB(
|
||||
sourceLocationUri(),
|
||||
Uri.file("/path/to/dir/dir.testproj"),
|
||||
);
|
||||
expect(await db.isAffectedByTest("/path/to/test.ql")).to.false;
|
||||
expect(await db.isAffectedByTest("/path/to/test.ql")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("findSourceArchive", function () {
|
||||
// not sure why, but some of these tests take more than two seconds to run.
|
||||
this.timeout(5000);
|
||||
|
||||
describe("findSourceArchive", () => {
|
||||
["src", "output/src_archive"].forEach((name) => {
|
||||
it(`should find source folder in ${name}`, async () => {
|
||||
const uri = Uri.file(path.join(dir.name, name));
|
||||
fs.createFileSync(path.join(uri.fsPath, "hucairz.txt"));
|
||||
const srcUri = await findSourceArchive(dir.name);
|
||||
expect(srcUri!.fsPath).to.eq(uri.fsPath);
|
||||
expect(srcUri!.fsPath).toBe(uri.fsPath);
|
||||
});
|
||||
|
||||
it(`should find source archive in ${name}.zip`, async () => {
|
||||
const uri = Uri.file(path.join(dir.name, name + ".zip"));
|
||||
fs.createFileSync(uri.fsPath);
|
||||
const srcUri = await findSourceArchive(dir.name);
|
||||
expect(srcUri!.fsPath).to.eq(uri.fsPath);
|
||||
expect(srcUri!.fsPath).toBe(uri.fsPath);
|
||||
});
|
||||
|
||||
it(`should prioritize ${name}.zip over ${name}`, async () => {
|
||||
@@ -540,7 +530,7 @@ describe("databases", () => {
|
||||
fs.createFileSync(path.join(uriFolder.fsPath, "hucairz.txt"));
|
||||
|
||||
const srcUri = await findSourceArchive(dir.name);
|
||||
expect(srcUri!.fsPath).to.eq(uri.fsPath);
|
||||
expect(srcUri!.fsPath).toBe(uri.fsPath);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -551,7 +541,7 @@ describe("databases", () => {
|
||||
fs.createFileSync(uriSrcArchive.fsPath);
|
||||
|
||||
const resultUri = await findSourceArchive(dir.name);
|
||||
expect(resultUri!.fsPath).to.eq(uriSrc.fsPath);
|
||||
expect(resultUri!.fsPath).toBe(uriSrc.fsPath);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -568,7 +558,7 @@ describe("databases", () => {
|
||||
datasetUri: databaseUri,
|
||||
} as DatabaseContents,
|
||||
MOCK_DB_OPTIONS,
|
||||
dbChangedHandler,
|
||||
() => void 0,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import * as vscode from "vscode";
|
||||
import { expect } from "chai";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs-extra";
|
||||
import * as pq from "proxyquire";
|
||||
import { DbConfig } from "../../../databases/config/db-config";
|
||||
import { DbManager } from "../../../databases/db-manager";
|
||||
import { DbConfigStore } from "../../../databases/config/db-config-store";
|
||||
import { DbTreeDataProvider } from "../../../databases/ui/db-tree-data-provider";
|
||||
import { DbPanel } from "../../../databases/ui/db-panel";
|
||||
import { DbItemKind, LocalDatabaseDbItem } from "../../../databases/db-item";
|
||||
import { DbTreeViewItem } from "../../../databases/ui/db-tree-view-item";
|
||||
import { ExtensionApp } from "../../../common/vscode/vscode-app";
|
||||
import { createMockExtensionContext } from "../../factories/extension-context";
|
||||
|
||||
const proxyquire = pq.noPreserveCache();
|
||||
|
||||
describe("db panel", async () => {
|
||||
describe("db panel", () => {
|
||||
const workspaceStoragePath = path.join(__dirname, "test-workspace-storage");
|
||||
const globalStoragePath = path.join(__dirname, "test-global-storage");
|
||||
const extensionPath = path.join(__dirname, "../../../../");
|
||||
@@ -26,9 +21,8 @@ describe("db panel", async () => {
|
||||
let dbTreeDataProvider: DbTreeDataProvider;
|
||||
let dbManager: DbManager;
|
||||
let dbConfigStore: DbConfigStore;
|
||||
let dbPanel: DbPanel;
|
||||
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const extensionContext = createMockExtensionContext({
|
||||
extensionPath,
|
||||
globalStoragePath,
|
||||
@@ -40,22 +34,6 @@ describe("db panel", async () => {
|
||||
|
||||
dbConfigStore = new DbConfigStore(app);
|
||||
dbManager = new DbManager(app, dbConfigStore);
|
||||
|
||||
// Create a modified version of the DbPanel module that allows
|
||||
// us to override the creation of the DbTreeDataProvider
|
||||
const mod = proxyquire("../../../databases/ui/db-panel", {
|
||||
"./db-tree-data-provider": {
|
||||
DbTreeDataProvider: class {
|
||||
constructor() {
|
||||
return dbTreeDataProvider;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Initialize the panel using the modified module
|
||||
dbPanel = new mod.DbPanel(dbManager) as DbPanel;
|
||||
await dbPanel.initialize();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -85,39 +63,39 @@ describe("db panel", async () => {
|
||||
|
||||
const dbTreeItems = await dbTreeDataProvider.getChildren();
|
||||
|
||||
expect(dbTreeItems).to.be.ok;
|
||||
expect(dbTreeItems).toBeTruthy();
|
||||
const items = dbTreeItems!;
|
||||
expect(items.length).to.equal(2);
|
||||
expect(items.length).toBe(2);
|
||||
|
||||
const remoteRootNode = items[0];
|
||||
expect(remoteRootNode.dbItem).to.be.ok;
|
||||
expect(remoteRootNode.dbItem?.kind).to.equal(DbItemKind.RootRemote);
|
||||
expect(remoteRootNode.label).to.equal("remote");
|
||||
expect(remoteRootNode.tooltip).to.equal("Remote databases");
|
||||
expect(remoteRootNode.collapsibleState).to.equal(
|
||||
expect(remoteRootNode.dbItem).toBeTruthy();
|
||||
expect(remoteRootNode.dbItem?.kind).toBe(DbItemKind.RootRemote);
|
||||
expect(remoteRootNode.label).toBe("remote");
|
||||
expect(remoteRootNode.tooltip).toBe("Remote databases");
|
||||
expect(remoteRootNode.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(remoteRootNode.children).to.be.ok;
|
||||
expect(remoteRootNode.children.length).to.equal(3);
|
||||
expect(remoteRootNode.children).toBeTruthy();
|
||||
expect(remoteRootNode.children.length).toBe(3);
|
||||
|
||||
const systemDefinedListItems = remoteRootNode.children.filter(
|
||||
(item) => item.dbItem?.kind === DbItemKind.RemoteSystemDefinedList,
|
||||
);
|
||||
expect(systemDefinedListItems.length).to.equal(3);
|
||||
expect(systemDefinedListItems.length).toBe(3);
|
||||
checkRemoteSystemDefinedListItem(systemDefinedListItems[0], 10);
|
||||
checkRemoteSystemDefinedListItem(systemDefinedListItems[1], 100);
|
||||
checkRemoteSystemDefinedListItem(systemDefinedListItems[2], 1000);
|
||||
|
||||
const localRootNode = items[1];
|
||||
expect(localRootNode.dbItem).to.be.ok;
|
||||
expect(localRootNode.dbItem?.kind).to.equal(DbItemKind.RootLocal);
|
||||
expect(localRootNode.label).to.equal("local");
|
||||
expect(localRootNode.tooltip).to.equal("Local databases");
|
||||
expect(localRootNode.collapsibleState).to.equal(
|
||||
expect(localRootNode.dbItem).toBeTruthy();
|
||||
expect(localRootNode.dbItem?.kind).toBe(DbItemKind.RootLocal);
|
||||
expect(localRootNode.label).toBe("local");
|
||||
expect(localRootNode.tooltip).toBe("Local databases");
|
||||
expect(localRootNode.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(localRootNode.children).to.be.ok;
|
||||
expect(localRootNode.children.length).to.equal(0);
|
||||
expect(localRootNode.children).toBeTruthy();
|
||||
expect(localRootNode.children.length).toBe(0);
|
||||
});
|
||||
|
||||
it("should render remote repository list nodes", async () => {
|
||||
@@ -148,27 +126,27 @@ describe("db panel", async () => {
|
||||
|
||||
const dbTreeItems = await dbTreeDataProvider.getChildren();
|
||||
|
||||
expect(dbTreeItems).to.be.ok;
|
||||
expect(dbTreeItems).toBeTruthy();
|
||||
const items = dbTreeItems!;
|
||||
expect(items.length).to.equal(2);
|
||||
expect(items.length).toBe(2);
|
||||
|
||||
const remoteRootNode = items[0];
|
||||
expect(remoteRootNode.dbItem).to.be.ok;
|
||||
expect(remoteRootNode.collapsibleState).to.equal(
|
||||
expect(remoteRootNode.dbItem).toBeTruthy();
|
||||
expect(remoteRootNode.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(remoteRootNode.children).to.be.ok;
|
||||
expect(remoteRootNode.children.length).to.equal(5);
|
||||
expect(remoteRootNode.children).toBeTruthy();
|
||||
expect(remoteRootNode.children.length).toBe(5);
|
||||
|
||||
const systemDefinedListItems = remoteRootNode.children.filter(
|
||||
(item) => item.dbItem?.kind === DbItemKind.RemoteSystemDefinedList,
|
||||
);
|
||||
expect(systemDefinedListItems.length).to.equal(3);
|
||||
expect(systemDefinedListItems.length).toBe(3);
|
||||
|
||||
const userDefinedListItems = remoteRootNode.children.filter(
|
||||
(item) => item.dbItem?.kind === DbItemKind.RemoteUserDefinedList,
|
||||
);
|
||||
expect(userDefinedListItems.length).to.equal(2);
|
||||
expect(userDefinedListItems.length).toBe(2);
|
||||
checkUserDefinedListItem(userDefinedListItems[0], "my-list-1", [
|
||||
"owner1/repo1",
|
||||
"owner1/repo2",
|
||||
@@ -199,22 +177,22 @@ describe("db panel", async () => {
|
||||
|
||||
const dbTreeItems = await dbTreeDataProvider.getChildren();
|
||||
|
||||
expect(dbTreeItems).to.be.ok;
|
||||
expect(dbTreeItems).toBeTruthy();
|
||||
const items = dbTreeItems!;
|
||||
expect(items.length).to.equal(2);
|
||||
expect(items.length).toBe(2);
|
||||
|
||||
const remoteRootNode = items[0];
|
||||
expect(remoteRootNode.dbItem).to.be.ok;
|
||||
expect(remoteRootNode.collapsibleState).to.equal(
|
||||
expect(remoteRootNode.dbItem).toBeTruthy();
|
||||
expect(remoteRootNode.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(remoteRootNode.children).to.be.ok;
|
||||
expect(remoteRootNode.children.length).to.equal(5);
|
||||
expect(remoteRootNode.children).toBeTruthy();
|
||||
expect(remoteRootNode.children.length).toBe(5);
|
||||
|
||||
const ownerListItems = remoteRootNode.children.filter(
|
||||
(item) => item.dbItem?.kind === DbItemKind.RemoteOwner,
|
||||
);
|
||||
expect(ownerListItems.length).to.equal(2);
|
||||
expect(ownerListItems.length).toBe(2);
|
||||
checkOwnerItem(ownerListItems[0], "owner1");
|
||||
checkOwnerItem(ownerListItems[1], "owner2");
|
||||
});
|
||||
@@ -238,22 +216,22 @@ describe("db panel", async () => {
|
||||
|
||||
const dbTreeItems = await dbTreeDataProvider.getChildren();
|
||||
|
||||
expect(dbTreeItems).to.be.ok;
|
||||
expect(dbTreeItems).toBeTruthy();
|
||||
const items = dbTreeItems!;
|
||||
expect(items.length).to.equal(2);
|
||||
expect(items.length).toBe(2);
|
||||
|
||||
const remoteRootNode = items[0];
|
||||
expect(remoteRootNode.dbItem).to.be.ok;
|
||||
expect(remoteRootNode.collapsibleState).to.equal(
|
||||
expect(remoteRootNode.dbItem).toBeTruthy();
|
||||
expect(remoteRootNode.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(remoteRootNode.children).to.be.ok;
|
||||
expect(remoteRootNode.children.length).to.equal(5);
|
||||
expect(remoteRootNode.children).toBeTruthy();
|
||||
expect(remoteRootNode.children.length).toBe(5);
|
||||
|
||||
const repoItems = remoteRootNode.children.filter(
|
||||
(item) => item.dbItem?.kind === DbItemKind.RemoteRepo,
|
||||
);
|
||||
expect(repoItems.length).to.equal(2);
|
||||
expect(repoItems.length).toBe(2);
|
||||
checkRemoteRepoItem(repoItems[0], "owner1/repo1");
|
||||
checkRemoteRepoItem(repoItems[1], "owner1/repo2");
|
||||
});
|
||||
@@ -306,22 +284,22 @@ describe("db panel", async () => {
|
||||
|
||||
const dbTreeItems = await dbTreeDataProvider.getChildren();
|
||||
|
||||
expect(dbTreeItems).to.be.ok;
|
||||
expect(dbTreeItems).toBeTruthy();
|
||||
const items = dbTreeItems!;
|
||||
expect(items.length).to.equal(2);
|
||||
expect(items.length).toBe(2);
|
||||
|
||||
const localRootNode = items[1];
|
||||
expect(localRootNode.dbItem).to.be.ok;
|
||||
expect(localRootNode.collapsibleState).to.equal(
|
||||
expect(localRootNode.dbItem).toBeTruthy();
|
||||
expect(localRootNode.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(localRootNode.children).to.be.ok;
|
||||
expect(localRootNode.children.length).to.equal(2);
|
||||
expect(localRootNode.children).toBeTruthy();
|
||||
expect(localRootNode.children.length).toBe(2);
|
||||
|
||||
const localListItems = localRootNode.children.filter(
|
||||
(item) => item.dbItem?.kind === DbItemKind.LocalList,
|
||||
);
|
||||
expect(localListItems.length).to.equal(2);
|
||||
expect(localListItems.length).toBe(2);
|
||||
checkLocalListItem(localListItems[0], "my-list-1", [
|
||||
{
|
||||
kind: DbItemKind.LocalDatabase,
|
||||
@@ -381,22 +359,22 @@ describe("db panel", async () => {
|
||||
|
||||
const dbTreeItems = await dbTreeDataProvider.getChildren();
|
||||
|
||||
expect(dbTreeItems).to.be.ok;
|
||||
expect(dbTreeItems).toBeTruthy();
|
||||
const items = dbTreeItems!;
|
||||
expect(items.length).to.equal(2);
|
||||
expect(items.length).toBe(2);
|
||||
|
||||
const localRootNode = items[1];
|
||||
expect(localRootNode.dbItem).to.be.ok;
|
||||
expect(localRootNode.collapsibleState).to.equal(
|
||||
expect(localRootNode.dbItem).toBeTruthy();
|
||||
expect(localRootNode.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(localRootNode.children).to.be.ok;
|
||||
expect(localRootNode.children.length).to.equal(2);
|
||||
expect(localRootNode.children).toBeTruthy();
|
||||
expect(localRootNode.children.length).toBe(2);
|
||||
|
||||
const localDatabaseItems = localRootNode.children.filter(
|
||||
(item) => item.dbItem?.kind === DbItemKind.LocalDatabase,
|
||||
);
|
||||
expect(localDatabaseItems.length).to.equal(2);
|
||||
expect(localDatabaseItems.length).toBe(2);
|
||||
checkLocalDatabaseItem(localDatabaseItems[0], {
|
||||
kind: DbItemKind.LocalDatabase,
|
||||
databaseName: "db1",
|
||||
@@ -428,12 +406,10 @@ describe("db panel", async () => {
|
||||
item: DbTreeViewItem,
|
||||
n: number,
|
||||
): void {
|
||||
expect(item.label).to.equal(`Top ${n} repositories`);
|
||||
expect(item.tooltip).to.equal(`Top ${n} repositories of a language`);
|
||||
expect(item.iconPath).to.deep.equal(new vscode.ThemeIcon("github"));
|
||||
expect(item.collapsibleState).to.equal(
|
||||
vscode.TreeItemCollapsibleState.None,
|
||||
);
|
||||
expect(item.label).toBe(`Top ${n} repositories`);
|
||||
expect(item.tooltip).toBe(`Top ${n} repositories of a language`);
|
||||
expect(item.iconPath).toEqual(new vscode.ThemeIcon("github"));
|
||||
expect(item.collapsibleState).toBe(vscode.TreeItemCollapsibleState.None);
|
||||
}
|
||||
|
||||
function checkUserDefinedListItem(
|
||||
@@ -441,14 +417,14 @@ describe("db panel", async () => {
|
||||
listName: string,
|
||||
repos: string[],
|
||||
): void {
|
||||
expect(item.label).to.equal(listName);
|
||||
expect(item.tooltip).to.be.undefined;
|
||||
expect(item.iconPath).to.be.undefined;
|
||||
expect(item.collapsibleState).to.equal(
|
||||
expect(item.label).toBe(listName);
|
||||
expect(item.tooltip).toBeUndefined();
|
||||
expect(item.iconPath).toBeUndefined();
|
||||
expect(item.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(item.children).to.be.ok;
|
||||
expect(item.children.length).to.equal(repos.length);
|
||||
expect(item.children).toBeTruthy();
|
||||
expect(item.children.length).toBe(repos.length);
|
||||
|
||||
for (let i = 0; i < repos.length; i++) {
|
||||
checkRemoteRepoItem(item.children[i], repos[i]);
|
||||
@@ -456,23 +432,19 @@ describe("db panel", async () => {
|
||||
}
|
||||
|
||||
function checkOwnerItem(item: DbTreeViewItem, ownerName: string): void {
|
||||
expect(item.label).to.equal(ownerName);
|
||||
expect(item.tooltip).to.be.undefined;
|
||||
expect(item.iconPath).to.deep.equal(new vscode.ThemeIcon("organization"));
|
||||
expect(item.collapsibleState).to.equal(
|
||||
vscode.TreeItemCollapsibleState.None,
|
||||
);
|
||||
expect(item.children).to.be.ok;
|
||||
expect(item.children.length).to.equal(0);
|
||||
expect(item.label).toBe(ownerName);
|
||||
expect(item.tooltip).toBeUndefined();
|
||||
expect(item.iconPath).toEqual(new vscode.ThemeIcon("organization"));
|
||||
expect(item.collapsibleState).toBe(vscode.TreeItemCollapsibleState.None);
|
||||
expect(item.children).toBeTruthy();
|
||||
expect(item.children.length).toBe(0);
|
||||
}
|
||||
|
||||
function checkRemoteRepoItem(item: DbTreeViewItem, repoName: string): void {
|
||||
expect(item.label).to.equal(repoName);
|
||||
expect(item.tooltip).to.be.undefined;
|
||||
expect(item.iconPath).to.deep.equal(new vscode.ThemeIcon("database"));
|
||||
expect(item.collapsibleState).to.equal(
|
||||
vscode.TreeItemCollapsibleState.None,
|
||||
);
|
||||
expect(item.label).toBe(repoName);
|
||||
expect(item.tooltip).toBeUndefined();
|
||||
expect(item.iconPath).toEqual(new vscode.ThemeIcon("database"));
|
||||
expect(item.collapsibleState).toBe(vscode.TreeItemCollapsibleState.None);
|
||||
}
|
||||
|
||||
function checkLocalListItem(
|
||||
@@ -480,14 +452,14 @@ describe("db panel", async () => {
|
||||
listName: string,
|
||||
databases: LocalDatabaseDbItem[],
|
||||
): void {
|
||||
expect(item.label).to.equal(listName);
|
||||
expect(item.tooltip).to.be.undefined;
|
||||
expect(item.iconPath).to.be.undefined;
|
||||
expect(item.collapsibleState).to.equal(
|
||||
expect(item.label).toBe(listName);
|
||||
expect(item.tooltip).toBeUndefined();
|
||||
expect(item.iconPath).toBeUndefined();
|
||||
expect(item.collapsibleState).toBe(
|
||||
vscode.TreeItemCollapsibleState.Collapsed,
|
||||
);
|
||||
expect(item.children).to.be.ok;
|
||||
expect(item.children.length).to.equal(databases.length);
|
||||
expect(item.children).toBeTruthy();
|
||||
expect(item.children.length).toBe(databases.length);
|
||||
|
||||
for (let i = 0; i < databases.length; i++) {
|
||||
checkLocalDatabaseItem(item.children[i], databases[i]);
|
||||
@@ -498,11 +470,9 @@ describe("db panel", async () => {
|
||||
item: DbTreeViewItem,
|
||||
database: LocalDatabaseDbItem,
|
||||
): void {
|
||||
expect(item.label).to.equal(database.databaseName);
|
||||
expect(item.tooltip).to.equal(`Language: ${database.language}`);
|
||||
expect(item.iconPath).to.deep.equal(new vscode.ThemeIcon("database"));
|
||||
expect(item.collapsibleState).to.equal(
|
||||
vscode.TreeItemCollapsibleState.None,
|
||||
);
|
||||
expect(item.label).toBe(database.databaseName);
|
||||
expect(item.tooltip).toBe(`Language: ${database.language}`);
|
||||
expect(item.iconPath).toEqual(new vscode.ThemeIcon("database"));
|
||||
expect(item.collapsibleState).toBe(vscode.TreeItemCollapsibleState.None);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { expect } from "chai";
|
||||
import * as path from "path";
|
||||
import * as vscode from "vscode";
|
||||
import { Uri } from "vscode";
|
||||
@@ -13,51 +12,49 @@ async function showQlDocument(name: string): Promise<vscode.TextDocument> {
|
||||
}
|
||||
|
||||
export function run() {
|
||||
describe("Determining selected query", async () => {
|
||||
describe("Determining selected query", () => {
|
||||
it("should allow ql files to be queried", async () => {
|
||||
const q = await determineSelectedQuery(
|
||||
Uri.parse("file:///tmp/queryname.ql"),
|
||||
false,
|
||||
);
|
||||
expect(q.queryPath).to.equal(path.join("/", "tmp", "queryname.ql"));
|
||||
expect(q.quickEvalPosition).to.equal(undefined);
|
||||
expect(q.queryPath).toBe(path.join("/", "tmp", "queryname.ql"));
|
||||
expect(q.quickEvalPosition).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should allow ql files to be quick-evaled", async () => {
|
||||
const doc = await showQlDocument("query.ql");
|
||||
const q = await determineSelectedQuery(doc.uri, true);
|
||||
expect(q.queryPath).to.satisfy((p: string) =>
|
||||
p.endsWith(path.join("ql-vscode", "test", "data", "query.ql")),
|
||||
);
|
||||
expect(
|
||||
q.queryPath.endsWith(
|
||||
path.join("ql-vscode", "test", "data", "query.ql"),
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("should allow qll files to be quick-evaled", async () => {
|
||||
const doc = await showQlDocument("library.qll");
|
||||
const q = await determineSelectedQuery(doc.uri, true);
|
||||
expect(q.queryPath).to.satisfy((p: string) =>
|
||||
p.endsWith(path.join("ql-vscode", "test", "data", "library.qll")),
|
||||
);
|
||||
expect(
|
||||
q.queryPath.endsWith(
|
||||
path.join("ql-vscode", "test", "data", "library.qll"),
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("should reject non-ql files when running a query", async () => {
|
||||
await expect(
|
||||
determineSelectedQuery(Uri.parse("file:///tmp/queryname.txt"), false),
|
||||
).to.be.rejectedWith(
|
||||
Error,
|
||||
"The selected resource is not a CodeQL query file",
|
||||
);
|
||||
).rejects.toThrow("The selected resource is not a CodeQL query file");
|
||||
await expect(
|
||||
determineSelectedQuery(Uri.parse("file:///tmp/queryname.qll"), false),
|
||||
).to.be.rejectedWith(
|
||||
Error,
|
||||
"The selected resource is not a CodeQL query file",
|
||||
);
|
||||
).rejects.toThrow("The selected resource is not a CodeQL query file");
|
||||
});
|
||||
|
||||
it("should reject non-ql[l] files when running a quick eval", async () => {
|
||||
await expect(
|
||||
determineSelectedQuery(Uri.parse("file:///tmp/queryname.txt"), true),
|
||||
).to.be.rejectedWith(Error, "The selected resource is not a CodeQL file");
|
||||
).rejects.toThrow("The selected resource is not a CodeQL file");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import "source-map-support/register";
|
||||
import * as sinonChai from "sinon-chai";
|
||||
import * as chai from "chai";
|
||||
import "chai/register-should";
|
||||
import * as chaiAsPromised from "chai-as-promised";
|
||||
|
||||
import { runTestsInDirectory } from "../index-template";
|
||||
|
||||
chai.use(chaiAsPromised);
|
||||
chai.use(sinonChai);
|
||||
|
||||
export function run(): Promise<void> {
|
||||
return runTestsInDirectory(__dirname);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import * as path from "path";
|
||||
import { RunnerOptions } from "jest-runner-vscode";
|
||||
|
||||
import baseConfig, { rootDir } from "../jest-runner-vscode.config.base";
|
||||
|
||||
const config: RunnerOptions = {
|
||||
...baseConfig,
|
||||
launchArgs: [
|
||||
...(baseConfig.launchArgs ?? []),
|
||||
"--disable-extensions",
|
||||
path.resolve(rootDir, "test/data"),
|
||||
],
|
||||
};
|
||||
|
||||
// We are purposefully not using export default here since that would result in an ESModule, which doesn't seem to be
|
||||
// supported properly by jest-runner-vscode (cosmiconfig doesn't really seem to support it).
|
||||
module.exports = config;
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Config } from "jest";
|
||||
|
||||
import baseConfig from "../jest.config.base";
|
||||
|
||||
const config: Config = {
|
||||
...baseConfig,
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,14 +1,10 @@
|
||||
import { Uri, WorkspaceFolder } from "vscode";
|
||||
import { expect } from "chai";
|
||||
import * as fs from "fs-extra";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import { QLTestDiscovery } from "../../qltest-discovery";
|
||||
|
||||
describe("qltest-discovery", () => {
|
||||
describe("discoverTests", () => {
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
|
||||
const baseUri = Uri.parse("file:/a/b");
|
||||
const baseDir = baseUri.fsPath;
|
||||
const cDir = Uri.parse("file:/a/b/c").fsPath;
|
||||
@@ -19,7 +15,6 @@ describe("qltest-discovery", () => {
|
||||
let qlTestDiscover: QLTestDiscovery;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
qlTestDiscover = new QLTestDiscovery(
|
||||
{
|
||||
uri: baseUri,
|
||||
@@ -37,47 +32,48 @@ describe("qltest-discovery", () => {
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it("should run discovery", async () => {
|
||||
sandbox.stub(fs, "pathExists").resolves(true);
|
||||
jest
|
||||
.spyOn(fs, "pathExists")
|
||||
.mockImplementation(() => Promise.resolve(true));
|
||||
|
||||
const result = await (qlTestDiscover as any).discover();
|
||||
expect(result.watchPath).to.eq(baseDir);
|
||||
expect(result.testDirectory.path).to.eq(baseDir);
|
||||
expect(result.testDirectory.name).to.eq("My tests");
|
||||
expect(result.watchPath).toBe(baseDir);
|
||||
expect(result.testDirectory.path).toBe(baseDir);
|
||||
expect(result.testDirectory.name).toBe("My tests");
|
||||
|
||||
let children = result.testDirectory.children;
|
||||
expect(children[0].path).to.eq(cDir);
|
||||
expect(children[0].name).to.eq("c");
|
||||
expect(children.length).to.eq(1);
|
||||
expect(children[0].path).toBe(cDir);
|
||||
expect(children[0].name).toBe("c");
|
||||
expect(children.length).toBe(1);
|
||||
|
||||
children = children[0].children;
|
||||
expect(children[0].path).to.eq(dFile);
|
||||
expect(children[0].name).to.eq("d.ql");
|
||||
expect(children[1].path).to.eq(eFile);
|
||||
expect(children[1].name).to.eq("e.ql");
|
||||
expect(children[0].path).toBe(dFile);
|
||||
expect(children[0].name).toBe("d.ql");
|
||||
expect(children[1].path).toBe(eFile);
|
||||
expect(children[1].name).toBe("e.ql");
|
||||
|
||||
// A merged foler
|
||||
expect(children[2].path).to.eq(hDir);
|
||||
expect(children[2].name).to.eq("f / g / h");
|
||||
expect(children.length).to.eq(3);
|
||||
expect(children[2].path).toBe(hDir);
|
||||
expect(children[2].name).toBe("f / g / h");
|
||||
expect(children.length).toBe(3);
|
||||
|
||||
children = children[2].children;
|
||||
expect(children[0].path).to.eq(iFile);
|
||||
expect(children[0].name).to.eq("i.ql");
|
||||
expect(children[0].path).toBe(iFile);
|
||||
expect(children[0].name).toBe("i.ql");
|
||||
});
|
||||
|
||||
it("should avoid discovery if a folder does not exist", async () => {
|
||||
sandbox.stub(fs, "pathExists").resolves(false);
|
||||
const result = await (qlTestDiscover as any).discover();
|
||||
expect(result.watchPath).to.eq(baseDir);
|
||||
expect(result.testDirectory.path).to.eq(baseDir);
|
||||
expect(result.testDirectory.name).to.eq("My tests");
|
||||
jest
|
||||
.spyOn(fs, "pathExists")
|
||||
.mockImplementation(() => Promise.resolve(false));
|
||||
|
||||
expect(result.testDirectory.children.length).to.eq(0);
|
||||
const result = await (qlTestDiscover as any).discover();
|
||||
expect(result.watchPath).toBe(baseDir);
|
||||
expect(result.testDirectory.path).toBe(baseDir);
|
||||
expect(result.testDirectory.name).toBe("My tests");
|
||||
|
||||
expect(result.testDirectory.children.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user