Merge pull request #2102 from github/koesie10/mock-objects
Add new `mockedObject` function
This commit is contained in:
@@ -105,7 +105,7 @@ export function transformBqrsResultSet(
|
||||
};
|
||||
}
|
||||
|
||||
type BqrsKind =
|
||||
export type BqrsKind =
|
||||
| "String"
|
||||
| "Float"
|
||||
| "Integer"
|
||||
|
||||
@@ -4,13 +4,13 @@ import { join } from "path";
|
||||
import { CancellationToken, ExtensionContext, Uri, workspace } from "vscode";
|
||||
|
||||
import {
|
||||
DatabaseEventKind,
|
||||
DatabaseManager,
|
||||
DatabaseItemImpl,
|
||||
DatabaseContents,
|
||||
FullDatabaseOptions,
|
||||
findSourceArchive,
|
||||
DatabaseEventKind,
|
||||
DatabaseItemImpl,
|
||||
DatabaseManager,
|
||||
DatabaseResolver,
|
||||
findSourceArchive,
|
||||
FullDatabaseOptions,
|
||||
} from "../../../src/local-databases";
|
||||
import { Logger } from "../../../src/common";
|
||||
import { ProgressCallback } from "../../../src/commandRunner";
|
||||
@@ -24,6 +24,7 @@ import { QueryRunner } from "../../../src/queryRunner";
|
||||
import * as helpers from "../../../src/helpers";
|
||||
import { Setting } from "../../../src/config";
|
||||
import { QlPackGenerator } from "../../../src/qlpack-generator";
|
||||
import { mockedObject } from "../utils/mocking.helpers";
|
||||
|
||||
describe("local databases", () => {
|
||||
const MOCK_DB_OPTIONS: FullDatabaseOptions = {
|
||||
@@ -77,20 +78,20 @@ describe("local databases", () => {
|
||||
|
||||
databaseManager = new DatabaseManager(
|
||||
extensionContext,
|
||||
{
|
||||
mockedObject<QueryRunner>({
|
||||
registerDatabase: registerSpy,
|
||||
deregisterDatabase: deregisterSpy,
|
||||
onStart: () => {
|
||||
/**/
|
||||
},
|
||||
} as unknown as QueryRunner,
|
||||
{
|
||||
}),
|
||||
mockedObject<CodeQLCliServer>({
|
||||
resolveDatabase: resolveDatabaseSpy,
|
||||
packAdd: packAddSpy,
|
||||
} as unknown as CodeQLCliServer,
|
||||
{
|
||||
}),
|
||||
mockedObject<Logger>({
|
||||
log: logSpy,
|
||||
} as unknown as Logger,
|
||||
}),
|
||||
);
|
||||
|
||||
// Unfortunately, during a test it is not possible to convert from
|
||||
|
||||
@@ -6,6 +6,7 @@ import { CodeQLCliServer } from "../../../src/cli";
|
||||
import { Uri, workspace } from "vscode";
|
||||
import { getErrorMessage } from "../../../src/pure/helpers-pure";
|
||||
import * as tmp from "tmp";
|
||||
import { mockedObject } from "../utils/mocking.helpers";
|
||||
|
||||
describe("QlPackGenerator", () => {
|
||||
let packFolderName: string;
|
||||
@@ -14,7 +15,7 @@ describe("QlPackGenerator", () => {
|
||||
let exampleQlFilePath: string;
|
||||
let language: string;
|
||||
let generator: QlPackGenerator;
|
||||
let packAddSpy: jest.SpyInstance;
|
||||
let packAddSpy: jest.Mock<any, []>;
|
||||
let dir: tmp.DirResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -28,9 +29,9 @@ describe("QlPackGenerator", () => {
|
||||
exampleQlFilePath = join(packFolderPath, "example.ql");
|
||||
|
||||
packAddSpy = jest.fn();
|
||||
const mockCli = {
|
||||
const mockCli = mockedObject<CodeQLCliServer>({
|
||||
packAdd: packAddSpy,
|
||||
} as unknown as CodeQLCliServer;
|
||||
});
|
||||
|
||||
generator = new QlPackGenerator(
|
||||
packFolderName,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { CodeQLCliServer } from "../../../../src/cli";
|
||||
import { DatabaseItem } from "../../../../src/local-databases";
|
||||
import { Uri } from "vscode";
|
||||
import { QueryWithResults } from "../../../../src/run-queries-shared";
|
||||
import { mockedObject } from "../../utils/mocking.helpers";
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -32,7 +33,7 @@ describe("AstBuilder", () => {
|
||||
let overrides: Record<string, Record<string, unknown> | undefined>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockCli = {
|
||||
mockCli = mockedObject<CodeQLCliServer>({
|
||||
bqrsDecode: jest
|
||||
.fn()
|
||||
.mockImplementation(
|
||||
@@ -40,7 +41,7 @@ describe("AstBuilder", () => {
|
||||
return mockDecode(resultSet);
|
||||
},
|
||||
),
|
||||
} as unknown as CodeQLCliServer;
|
||||
});
|
||||
overrides = {
|
||||
nodes: undefined,
|
||||
edges: undefined,
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from "../../../../src/contextual/queryResolver";
|
||||
import { CodeQLCliServer } from "../../../../src/cli";
|
||||
import { DatabaseItem } from "../../../../src/local-databases";
|
||||
import { mockedObject } from "../../utils/mocking.helpers";
|
||||
|
||||
describe("queryResolver", () => {
|
||||
let getQlPackForDbschemeSpy: jest.SpiedFunction<
|
||||
@@ -20,9 +21,11 @@ describe("queryResolver", () => {
|
||||
typeof helpers.getPrimaryDbscheme
|
||||
>;
|
||||
|
||||
const mockCli = {
|
||||
resolveQueriesInSuite: jest.fn(),
|
||||
};
|
||||
const resolveQueriesInSuite = jest.fn();
|
||||
|
||||
const mockCli = mockedObject<CodeQLCliServer>({
|
||||
resolveQueriesInSuite,
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
getQlPackForDbschemeSpy = jest
|
||||
@@ -41,20 +44,20 @@ describe("queryResolver", () => {
|
||||
|
||||
describe("resolveQueries", () => {
|
||||
it("should resolve a query", async () => {
|
||||
mockCli.resolveQueriesInSuite.mockReturnValue(["a", "b"]);
|
||||
resolveQueriesInSuite.mockReturnValue(["a", "b"]);
|
||||
const result = await resolveQueries(
|
||||
mockCli as unknown as CodeQLCliServer,
|
||||
mockCli,
|
||||
{ dbschemePack: "my-qlpack", dbschemePackIsLibraryPack: false },
|
||||
KeyType.DefinitionQuery,
|
||||
);
|
||||
expect(result).toEqual(["a", "b"]);
|
||||
|
||||
expect(mockCli.resolveQueriesInSuite).toHaveBeenCalledWith(
|
||||
expect(resolveQueriesInSuite).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/\.qls$/),
|
||||
[],
|
||||
);
|
||||
|
||||
const fileName = mockCli.resolveQueriesInSuite.mock.calls[0][0];
|
||||
const fileName = resolveQueriesInSuite.mock.calls[0][0];
|
||||
|
||||
expect(load(await fs.readFile(fileName, "utf-8"))).toEqual([
|
||||
{
|
||||
@@ -69,11 +72,11 @@ describe("queryResolver", () => {
|
||||
});
|
||||
|
||||
it("should throw an error when there are no queries found", async () => {
|
||||
mockCli.resolveQueriesInSuite.mockReturnValue([]);
|
||||
resolveQueriesInSuite.mockReturnValue([]);
|
||||
|
||||
try {
|
||||
await resolveQueries(
|
||||
mockCli as unknown as CodeQLCliServer,
|
||||
mockCli,
|
||||
{ dbschemePack: "my-qlpack", dbschemePackIsLibraryPack: false },
|
||||
KeyType.DefinitionQuery,
|
||||
);
|
||||
@@ -100,10 +103,7 @@ describe("queryResolver", () => {
|
||||
},
|
||||
},
|
||||
} as unknown as DatabaseItem;
|
||||
const result = await qlpackOfDatabase(
|
||||
mockCli as unknown as CodeQLCliServer,
|
||||
db,
|
||||
);
|
||||
const result = await qlpackOfDatabase(mockCli, db);
|
||||
expect(result).toEqual({
|
||||
dbschemePack: "my-qlpack",
|
||||
dbschemePackIsLibraryPack: false,
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
QueryResultType,
|
||||
} from "../../../src/pure/legacy-messages";
|
||||
import { sleep } from "../../../src/pure/time";
|
||||
import { mockedObject } from "../utils/mocking.helpers";
|
||||
|
||||
describe("query-results", () => {
|
||||
let queryPath: string;
|
||||
@@ -139,9 +140,9 @@ describe("query-results", () => {
|
||||
const completedQuery = fqi.completedQuery!;
|
||||
|
||||
const spy = jest.fn();
|
||||
const mockServer = {
|
||||
const mockServer = mockedObject<CodeQLCliServer>({
|
||||
sortBqrs: spy,
|
||||
} as unknown as CodeQLCliServer;
|
||||
});
|
||||
const sortState = {
|
||||
columnIndex: 1,
|
||||
sortDirection: SortDirection.desc,
|
||||
@@ -196,9 +197,9 @@ describe("query-results", () => {
|
||||
|
||||
await ensureDir(basename(interpretedResultsPath));
|
||||
|
||||
mockServer = {
|
||||
mockServer = mockedObject<CodeQLCliServer>({
|
||||
interpretBqrsSarif: spy,
|
||||
} as unknown as CodeQLCliServer;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
||||
@@ -16,6 +16,8 @@ import { SELECT_QUERY_NAME } from "../../../src/contextual/locationFinder";
|
||||
import { QueryInProgress } from "../../../src/legacy-query-server/run-queries";
|
||||
import { LegacyQueryRunner } from "../../../src/legacy-query-server/legacyRunner";
|
||||
import { DatabaseItem } from "../../../src/local-databases";
|
||||
import { DeepPartial, mockedObject } from "../utils/mocking.helpers";
|
||||
import { BqrsKind } from "../../../src/pure/bqrs-cli-types";
|
||||
|
||||
describe("run-queries", () => {
|
||||
let isCanarySpy: jest.SpiedFunction<typeof config.isCanary>;
|
||||
@@ -77,7 +79,7 @@ describe("run-queries", () => {
|
||||
],
|
||||
bqrsDecode: [
|
||||
{
|
||||
columns: [{ kind: "NotString" }, { kind: "String" }],
|
||||
columns: [{ kind: "NotString" as BqrsKind }, { kind: "String" }],
|
||||
tuples: [
|
||||
["a", "b"],
|
||||
["c", "d"],
|
||||
@@ -89,8 +91,8 @@ describe("run-queries", () => {
|
||||
// this won't happen with the real CLI, but it's a good test
|
||||
columns: [
|
||||
{ kind: "String" },
|
||||
{ kind: "NotString" },
|
||||
{ kind: "StillNotString" },
|
||||
{ kind: "NotString" as BqrsKind },
|
||||
{ kind: "StillNotString" as BqrsKind },
|
||||
],
|
||||
tuples: [["a", "b", "c"]],
|
||||
},
|
||||
@@ -125,7 +127,7 @@ describe("run-queries", () => {
|
||||
],
|
||||
bqrsDecode: [
|
||||
{
|
||||
columns: [{ kind: "NotString" }, { kind: "String" }],
|
||||
columns: [{ kind: "NotString" as BqrsKind }, { kind: "String" }],
|
||||
// We only escape string columns. In practice, we will only see quotes in strings, but
|
||||
// it is a good test anyway.
|
||||
tuples: [
|
||||
@@ -312,7 +314,7 @@ describe("run-queries", () => {
|
||||
function createMockQueryServerClient(
|
||||
cliServer?: CodeQLCliServer,
|
||||
): QueryServerClient {
|
||||
return {
|
||||
return mockedObject<QueryServerClient>({
|
||||
config: {
|
||||
timeoutSecs: 5,
|
||||
},
|
||||
@@ -326,20 +328,32 @@ describe("run-queries", () => {
|
||||
log: jest.fn(),
|
||||
},
|
||||
cliServer,
|
||||
} as unknown as QueryServerClient;
|
||||
});
|
||||
}
|
||||
|
||||
// A type that represents the mocked methods of a CodeQLCliServer. Exclude any non-methods.
|
||||
// This allows passing in an array of return values for a single method.
|
||||
type MockedCLIMethods = {
|
||||
[K in keyof CodeQLCliServer]: CodeQLCliServer[K] extends (
|
||||
...args: any
|
||||
) => any
|
||||
? Array<DeepPartial<Awaited<ReturnType<CodeQLCliServer[K]>>>>
|
||||
: never;
|
||||
};
|
||||
|
||||
function createMockCliServer(
|
||||
mockOperations: Record<string, any[]>,
|
||||
mockOperations: Partial<MockedCLIMethods>,
|
||||
): CodeQLCliServer {
|
||||
const mockServer: Record<string, any> = {};
|
||||
const mockedMethods: Record<string, jest.Mock> = {};
|
||||
|
||||
for (const [operation, returns] of Object.entries(mockOperations)) {
|
||||
mockServer[operation] = jest.fn();
|
||||
returns.forEach((returnValue) => {
|
||||
mockServer[operation].mockResolvedValueOnce(returnValue);
|
||||
const fn = jest.fn();
|
||||
returns.forEach((returnValue: any) => {
|
||||
fn.mockResolvedValueOnce(returnValue);
|
||||
});
|
||||
mockedMethods[operation] = fn;
|
||||
}
|
||||
|
||||
return mockServer as unknown as CodeQLCliServer;
|
||||
return mockedObject<CodeQLCliServer>(mockedMethods);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
DatabaseManager,
|
||||
FullDatabaseOptions,
|
||||
} from "../../../src/local-databases";
|
||||
import { mockedObject } from "../utils/mocking.helpers";
|
||||
|
||||
jest.mock("fs-extra", () => {
|
||||
const original = jest.requireActual("fs-extra");
|
||||
@@ -74,15 +75,15 @@ describe("test-adapter", () => {
|
||||
jest.spyOn(preTestDatabaseItem, "isAffectedByTest").mockResolvedValue(true);
|
||||
|
||||
adapter = new QLTestAdapter(
|
||||
{
|
||||
mockedObject<WorkspaceFolder>({
|
||||
name: "ABC",
|
||||
uri: Uri.parse("file:/ab/c"),
|
||||
} as WorkspaceFolder,
|
||||
{
|
||||
}),
|
||||
mockedObject<CodeQLCliServer>({
|
||||
runTests: runTestsSpy,
|
||||
resolveQlpacks: resolveQlpacksSpy,
|
||||
resolveTests: resolveTestsSpy,
|
||||
} as unknown as CodeQLCliServer,
|
||||
}),
|
||||
fakeDatabaseManager,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
export type DeepPartial<T> = T extends object
|
||||
? {
|
||||
[P in keyof T]?: DeepPartial<T[P]>;
|
||||
}
|
||||
: T;
|
||||
|
||||
export function mockedObject<T extends object>(props: DeepPartial<T>): T {
|
||||
return new Proxy<T>({} as unknown as T, {
|
||||
get: (_target, prop) => {
|
||||
if (prop in props) {
|
||||
return (props as any)[prop];
|
||||
}
|
||||
throw new Error(`Method ${String(prop)} not mocked`);
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user