Skip to content

Commit 3e3a31d

Browse files
committed
Add unit tests for query-results.ts
1 parent 72160a2 commit 3e3a31d

4 files changed

Lines changed: 308 additions & 48 deletions

File tree

extensions/ql-vscode/src/helpers.ts

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ import * as fs from 'fs-extra';
22
import * as glob from 'glob-promise';
33
import * as yaml from 'js-yaml';
44
import * as path from 'path';
5-
import { CancellationToken, ExtensionContext, ProgressOptions, window as Window, workspace } from 'vscode';
5+
import {
6+
CancellationToken,
7+
ExtensionContext,
8+
ProgressOptions,
9+
window as Window,
10+
workspace
11+
} from 'vscode';
612
import { CodeQLCliServer } from './cli';
713
import { logger } from './logging';
8-
import { QueryInfo } from './run-queries';
914

1015
export interface ProgressUpdate {
1116
/**
@@ -145,24 +150,6 @@ export function getOnDiskWorkspaceFolders() {
145150
return diskWorkspaceFolders;
146151
}
147152

148-
/**
149-
* Gets a human-readable name for an evaluated query.
150-
* Uses metadata if it exists, and defaults to the query file name.
151-
*/
152-
export function getQueryName(query: QueryInfo) {
153-
// Queries run through quick evaluation are not usually the entire query file.
154-
// Label them differently and include the line numbers.
155-
if (query.quickEvalPosition !== undefined) {
156-
const { line, endLine, fileName } = query.quickEvalPosition;
157-
const lineInfo = line === endLine ? `${line}` : `${line}-${endLine}`;
158-
return `Quick evaluation of ${path.basename(fileName)}:${lineInfo}`;
159-
} else if (query.metadata && query.metadata.name) {
160-
return query.metadata.name;
161-
} else {
162-
return path.basename(query.program.queryPath);
163-
}
164-
}
165-
166153
/**
167154
* Provides a utility method to invoke a function only if a minimum time interval has elapsed since
168155
* the last invocation of that function.

extensions/ql-vscode/src/interface.ts

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -365,14 +365,16 @@ export class InterfaceManager extends DisposableObject {
365365

366366
// Use sorted results path if it exists. This may happen if we are
367367
// reloading the results view after it has been sorted in the past.
368-
const resultsPath = results.sortedResultsInfo.get(selectedTable)?.resultsPath
369-
|| results.query.resultsPaths.resultsPath;
368+
const resultsPath = results.getResultsPath(selectedTable);
370369

371370
const chunk = await this.cliServer.bqrsDecode(
372371
resultsPath,
373372
schema.name,
374373
{
375-
// always use the first page. –
374+
// Always send the first page.
375+
// It may not wind up being the page we actually show,
376+
// if there are interpreted results, but speculatively
377+
// send anyway.
376378
offset: schema.pagination?.offsets[0],
377379
pageSize: RAW_RESULTS_PAGE_SIZE
378380
}
@@ -433,8 +435,7 @@ export class InterfaceManager extends DisposableObject {
433435
}
434436

435437
private async getResultSetSchemas(results: CompletedQuery, selectedTable = ''): Promise<ResultSetSchema[]> {
436-
const resultsPath = results.sortedResultsInfo.get(selectedTable)?.resultsPath
437-
|| results.query.resultsPaths.resultsPath;
438+
const resultsPath = results.getResultsPath(selectedTable);
438439
const schemas = await this.cliServer.bqrsInfo(
439440
resultsPath,
440441
RAW_RESULTS_PAGE_SIZE
@@ -470,21 +471,8 @@ export class InterfaceManager extends DisposableObject {
470471
if (schema === undefined)
471472
throw new Error(`Query result set '${selectedTable}' not found.`);
472473

473-
const getResultsPath = () => {
474-
if (sorted) {
475-
const resultsPath = results.sortedResultsInfo.get(selectedTable)?.resultsPath;
476-
if (resultsPath === undefined) {
477-
throw new Error(`Can't find sorted results for table ${selectedTable}`);
478-
}
479-
return resultsPath;
480-
}
481-
else {
482-
return results.query.resultsPaths.resultsPath;
483-
}
484-
};
485-
486474
const chunk = await this.cliServer.bqrsDecode(
487-
getResultsPath(),
475+
results.getResultsPath(selectedTable, sorted),
488476
schema.name,
489477
{
490478
offset: schema.pagination?.offsets[pageNumber],

extensions/ql-vscode/src/query-results.ts

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { env } from 'vscode';
22

33
import { QueryWithResults, tmpDir, QueryInfo } from './run-queries';
44
import * as messages from './messages';
5-
import * as helpers from './helpers';
65
import * as cli from './cli';
76
import * as sarif from 'sarif';
87
import * as fs from 'fs-extra';
@@ -53,7 +52,7 @@ export class CompletedQuery implements QueryWithResults {
5352
return this.database.name;
5453
}
5554
get queryName(): string {
56-
return helpers.getQueryName(this.query);
55+
return getQueryName(this.query);
5756
}
5857

5958
get statusString(): string {
@@ -72,6 +71,13 @@ export class CompletedQuery implements QueryWithResults {
7271
}
7372
}
7473

74+
getResultsPath(selectedTable: string, useSorted = true): string {
75+
if (!useSorted) {
76+
return this.query.resultsPaths.resultsPath;
77+
}
78+
return this.sortedResultsInfo.get(selectedTable)?.resultsPath
79+
|| this.query.resultsPaths.resultsPath;
80+
}
7581

7682
interpolate(template: string): string {
7783
const { databaseName, queryName, time, statusString } = this;
@@ -89,9 +95,8 @@ export class CompletedQuery implements QueryWithResults {
8995
}
9096

9197
getLabel(): string {
92-
if (this.options.label !== undefined)
93-
return this.options.label;
94-
return this.config.format;
98+
return this.options?.label
99+
|| this.config.format;
95100
}
96101

97102
get didRunSuccessfully(): boolean {
@@ -102,7 +107,11 @@ export class CompletedQuery implements QueryWithResults {
102107
return this.interpolate(this.getLabel());
103108
}
104109

105-
async updateSortState(server: cli.CodeQLCliServer, resultSetName: string, sortState: RawResultsSortState | undefined): Promise<void> {
110+
async updateSortState(
111+
server: cli.CodeQLCliServer,
112+
resultSetName: string,
113+
sortState?: RawResultsSortState
114+
): Promise<void> {
106115
if (sortState === undefined) {
107116
this.sortedResultsInfo.delete(resultSetName);
108117
return;
@@ -113,19 +122,50 @@ export class CompletedQuery implements QueryWithResults {
113122
sortState
114123
};
115124

116-
await server.sortBqrs(this.query.resultsPaths.resultsPath, sortedResultSetInfo.resultsPath, resultSetName, [sortState.columnIndex], [sortState.sortDirection]);
125+
await server.sortBqrs(
126+
this.query.resultsPaths.resultsPath,
127+
sortedResultSetInfo.resultsPath,
128+
resultSetName,
129+
[sortState.columnIndex],
130+
[sortState.sortDirection]
131+
);
117132
this.sortedResultsInfo.set(resultSetName, sortedResultSetInfo);
118133
}
119134

120-
async updateInterpretedSortState(sortState: InterpretedResultsSortState | undefined): Promise<void> {
135+
async updateInterpretedSortState(sortState?: InterpretedResultsSortState): Promise<void> {
121136
this.interpretedResultsSortState = sortState;
122137
}
123138
}
124139

140+
141+
/**
142+
* Gets a human-readable name for an evaluated query.
143+
* Uses metadata if it exists, and defaults to the query file name.
144+
*/
145+
export function getQueryName(query: QueryInfo) {
146+
// Queries run through quick evaluation are not usually the entire query file.
147+
// Label them differently and include the line numbers.
148+
if (query.quickEvalPosition !== undefined) {
149+
const { line, endLine, fileName } = query.quickEvalPosition;
150+
const lineInfo = line === endLine ? `${line}` : `${line}-${endLine}`;
151+
return `Quick evaluation of ${path.basename(fileName)}:${lineInfo}`;
152+
} else if (query.metadata?.name) {
153+
return query.metadata.name;
154+
} else {
155+
return path.basename(query.program.queryPath);
156+
}
157+
}
158+
159+
125160
/**
126161
* Call cli command to interpret results.
127162
*/
128-
export async function interpretResults(server: cli.CodeQLCliServer, metadata: QueryMetadata | undefined, resultsPaths: ResultsPaths, sourceInfo?: cli.SourceInfo): Promise<sarif.Log> {
163+
export async function interpretResults(
164+
server: cli.CodeQLCliServer,
165+
metadata: QueryMetadata | undefined,
166+
resultsPaths: ResultsPaths,
167+
sourceInfo?: cli.SourceInfo
168+
): Promise<sarif.Log> {
129169
const { resultsPath, interpretedResultsPath } = resultsPaths;
130170
if (await fs.pathExists(interpretedResultsPath)) {
131171
return JSON.parse(await fs.readFile(interpretedResultsPath, 'utf8'));

0 commit comments

Comments
 (0)