add tests and bugfixes - search API (#227652)

* add tests and bugfixes

* restore non-disposable file manager

* remove old test
This commit is contained in:
Andrea Mah
2024-09-05 13:55:09 -07:00
committed by GitHub
parent 66207ee728
commit 70da4627f7
6 changed files with 91 additions and 25 deletions
@@ -141,7 +141,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
// --- search ---
$startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<UriComponents[] | null> {
$startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions<UriComponents>, token: CancellationToken): Promise<UriComponents[] | null> {
const includeFolder = URI.revive(_includeFolder);
const workspace = this._contextService.getWorkspace();
@@ -160,7 +160,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
});
}
$startTextSearch(pattern: IPatternInfo, _folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
$startTextSearch(pattern: IPatternInfo, _folder: UriComponents | null, options: ITextQueryBuilderOptions<UriComponents>, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
const folder = URI.revive(_folder);
const workspace = this._contextService.getWorkspace();
const folders = folder ? [folder] : workspace.folders.map(folder => folder.uri);
@@ -987,9 +987,9 @@ interface IExtensionListener<E> {
(e: E): any;
}
function globsToISearchPatternBuilder(excludes: vscode.GlobPattern[] | undefined): ISearchPatternBuilder[] {
function globsToISearchPatternBuilder(excludes: vscode.GlobPattern[] | undefined): ISearchPatternBuilder<URI>[] {
return (
excludes?.map((exclude): ISearchPatternBuilder | undefined => {
excludes?.map((exclude): ISearchPatternBuilder<URI> | undefined => {
if (typeof exclude === 'string') {
if (exclude === '') {
return undefined;
@@ -997,7 +997,7 @@ function globsToISearchPatternBuilder(excludes: vscode.GlobPattern[] | undefined
return {
pattern: exclude,
uri: undefined
} satisfies ISearchPatternBuilder;
} satisfies ISearchPatternBuilder<URI>;
} else {
const parsedExclude = parseSearchExcludeInclude(exclude);
if (!parsedExclude) {
@@ -1006,8 +1006,8 @@ function globsToISearchPatternBuilder(excludes: vscode.GlobPattern[] | undefined
return {
pattern: parsedExclude.pattern,
uri: parsedExclude.folder
} satisfies ISearchPatternBuilder;
} satisfies ISearchPatternBuilder<URI>;
}
}) ?? []
).filter((e): e is ISearchPatternBuilder => !!e);
).filter((e): e is ISearchPatternBuilder<URI> => !!e);
}
@@ -13,6 +13,7 @@ import { MainThreadWorkspace } from '../../browser/mainThreadWorkspace.js';
import { SingleProxyRPCProtocol } from '../common/testRPCProtocol.js';
import { IFileQuery, ISearchService } from '../../../services/search/common/search.js';
import { workbenchInstantiationService } from '../../../test/browser/workbenchTestServices.js';
import { URI, UriComponents } from '../../../../base/common/uri.js';
suite('MainThreadWorkspace', () => {
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
@@ -123,4 +124,23 @@ suite('MainThreadWorkspace', () => {
const mtw = disposables.add(instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })));
return mtw.$startFileSearch(null, { maxResults: 10, includePattern: '', excludePattern: [{ pattern: 'exclude/**' }], disregardSearchExcludeSettings: true }, CancellationToken.None);
});
test('Valid revived URI after moving to EH', () => {
const uriComponents: UriComponents = {
scheme: 'test',
path: '/Users/username/Downloads',
};
instantiationService.stub(ISearchService, {
fileSearch(query: IFileQuery) {
assert.strictEqual(query.folderQueries?.length, 1);
assert.ok(URI.isUri(query.folderQueries[0].folder));
assert.strictEqual(query.folderQueries[0].folder.path, '/Users/username/Downloads');
assert.strictEqual(query.folderQueries[0].folder.scheme, 'test');
return Promise.resolve({ results: [], messages: [] });
}
});
const mtw = disposables.add(instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })));
return mtw.$startFileSearch(uriComponents, { filePattern: '*.md' }, CancellationToken.None);
});
});
@@ -263,6 +263,28 @@ suite('ExtHostSearch', () => {
assert(!results.length);
});
test('session cancellation should work', async () => {
let numSessionCancelled = 0;
const disposables: (vscode.Disposable | undefined)[] = [];
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<URI[]> {
disposables.push(options.session?.onCancellationRequested(() => {
numSessionCancelled++;
}));
return Promise.resolve([]);
}
});
await runFileSearch({ ...getSimpleQuery(), cacheKey: '1' }, true);
await runFileSearch({ ...getSimpleQuery(), cacheKey: '2' }, true);
extHostSearch.$clearCache('1');
assert.strictEqual(numSessionCancelled, 1);
disposables.forEach(d => d?.dispose());
});
test('provider returns null', async () => {
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<URI[]> {
@@ -702,6 +724,24 @@ suite('ExtHostSearch', () => {
const { results } = await runFileSearch(query);
compareURIs(results, reportedResults);
});
test('if onlyFileScheme is set, do not call custom schemes', async () => {
let fancySchemeCalled = false;
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<URI[]> {
fancySchemeCalled = true;
return Promise.resolve([]);
}
}, fancyScheme);
const query: ISearchQuery = {
type: QueryType.File,
filePattern: '',
folderQueries: []
};
await runFileSearch(query);
assert(!fancySchemeCalled);
});
});
suite('Text:', () => {
@@ -13,7 +13,6 @@ import { URI } from '../../../../base/common/uri.js';
import { IFileMatch, IFileSearchProviderStats, IFolderQuery, ISearchCompleteStats, IFileQuery, QueryGlobTester, resolvePatternsForProvider, hasSiblingFn, excludeToGlobPattern, DEFAULT_MAX_SEARCH_RESULTS } from './search.js';
import { FileSearchProviderFolderOptions, FileSearchProviderNew, FileSearchProviderOptions } from './searchExtTypes.js';
import { TernarySearchTree } from '../../../../base/common/ternarySearchTree.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { OldFileSearchProviderConverter } from './searchExtConversionTypes.js';
interface IInternalFileMatch {
@@ -307,19 +306,26 @@ interface IInternalSearchComplete {
/**
* For backwards compatibility, store both a cancellation token and a session object. The session object is the new implementation, where
*/
class SessionLifecycle extends Disposable {
public readonly obj: object;
class SessionLifecycle {
private _obj: object | undefined;
public readonly tokenSource: CancellationTokenSource;
constructor() {
super();
this.obj = new Object();
this._obj = new Object();
this.tokenSource = new CancellationTokenSource();
}
public override dispose(): void {
public get obj() {
if (this._obj) {
return this._obj;
}
throw new Error('Session object has been dereferenced.');
}
cancel() {
this.tokenSource.cancel();
super.dispose();
this._obj = undefined; // dereference
}
}
@@ -356,7 +362,7 @@ export class FileSearchManager {
clearCache(cacheKey: string): void {
// cancel the token
this.sessions.get(cacheKey)?.dispose();
this.sessions.get(cacheKey)?.cancel();
// with no reference to this, it will be removed from WeakMaps
this.sessions.delete(cacheKey);
}
@@ -13,7 +13,7 @@ import * as path from '../../../../base/common/path.js';
import { isEqual, basename, relativePath, isAbsolutePath } from '../../../../base/common/resources.js';
import * as strings from '../../../../base/common/strings.js';
import { assertIsDefined, isDefined } from '../../../../base/common/types.js';
import { URI, URI as uri } from '../../../../base/common/uri.js';
import { URI, URI as uri, UriComponents } from '../../../../base/common/uri.js';
import { isMultilineRegexSource } from '../../../../editor/common/model/textModelSearch.js';
import * as nls from '../../../../nls.js';
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
@@ -43,16 +43,16 @@ export interface ISearchPathPattern {
type ISearchPathPatternBuilder = string | string[];
export interface ISearchPatternBuilder {
uri?: uri;
export interface ISearchPatternBuilder<U extends UriComponents> {
uri?: U;
pattern: ISearchPathPatternBuilder;
}
export function isISearchPatternBuilder(object: ISearchPatternBuilder | ISearchPathPatternBuilder): object is ISearchPatternBuilder {
export function isISearchPatternBuilder<U extends UriComponents>(object: ISearchPatternBuilder<U> | ISearchPathPatternBuilder): object is ISearchPatternBuilder<U> {
return (typeof object === 'object' && 'uri' in object && 'pattern' in object);
}
export function globPatternToISearchPatternBuilder(globPattern: GlobPattern): ISearchPatternBuilder {
export function globPatternToISearchPatternBuilder(globPattern: GlobPattern): ISearchPatternBuilder<URI> {
if (typeof globPattern === 'string') {
return {
@@ -74,11 +74,11 @@ export interface ISearchPathsInfo {
pattern?: glob.IExpression;
}
interface ICommonQueryBuilderOptions {
interface ICommonQueryBuilderOptions<U extends UriComponents = URI> {
_reason?: string;
excludePattern?: ISearchPatternBuilder[];
excludePattern?: ISearchPatternBuilder<U>[];
includePattern?: ISearchPathPatternBuilder;
extraFileResources?: uri[];
extraFileResources?: U[];
/** Parse the special ./ syntax supported by the searchview, and expand foo to ** /foo */
expandPatterns?: boolean;
@@ -95,7 +95,7 @@ interface ICommonQueryBuilderOptions {
onlyFileScheme?: boolean;
}
export interface IFileQueryBuilderOptions extends ICommonQueryBuilderOptions {
export interface IFileQueryBuilderOptions<U extends UriComponents = URI> extends ICommonQueryBuilderOptions<U> {
filePattern?: string;
exists?: boolean;
sortByScore?: boolean;
@@ -103,7 +103,7 @@ export interface IFileQueryBuilderOptions extends ICommonQueryBuilderOptions {
shouldGlobSearch?: boolean;
}
export interface ITextQueryBuilderOptions extends ICommonQueryBuilderOptions {
export interface ITextQueryBuilderOptions<U extends UriComponents = URI> extends ICommonQueryBuilderOptions<U> {
previewOptions?: ITextSearchPreviewOptions;
fileEncoding?: string;
surroundingContext?: number;