提交 ce19a2f3 编写于 作者: B Benjamin Pasero

Merge branch 'master' into ben/16591

......@@ -312,7 +312,7 @@ export function isUNC(path: string): boolean {
}
// Reference: https://en.wikipedia.org/wiki/Filename
const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g;
const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[/]/g;
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i;
export function isValidBasename(name: string): boolean {
if (!name || name.length === 0 || /^\s+$/.test(name)) {
......
......@@ -8,7 +8,6 @@
import { BoundedLinkedMap, LRUCache, LinkedMap, TrieMap, ResourceMap } from 'vs/base/common/map';
import * as assert from 'assert';
import URI from 'vs/base/common/uri';
import { isLinux } from 'vs/base/common/platform';
suite('Map', () => {
......@@ -402,6 +401,35 @@ suite('Map', () => {
assert.ok(map.has(resource2));
});
test('ResourceMap - files (do NOT ignorecase)', function () {
const map = new ResourceMap<any>();
const fileA = URI.parse('file://some/filea');
const fileB = URI.parse('some://some/other/fileb');
const fileAUpper = URI.parse('file://SOME/FILEA');
map.set(fileA, 'true');
assert.equal(map.get(fileA), 'true');
assert.ok(!map.get(fileAUpper));
assert.ok(!map.get(fileB));
map.set(fileAUpper, 'false');
assert.equal(map.get(fileAUpper), 'false');
assert.equal(map.get(fileA), 'true');
const windowsFile = URI.file('c:\\test with %25\\c#code');
const uncFile = URI.file('\\\\shäres\\path\\c#\\plugin.json');
map.set(windowsFile, 'true');
map.set(uncFile, 'true');
assert.equal(map.get(windowsFile), 'true');
assert.equal(map.get(uncFile), 'true');
});
test('ResourceMap - files (ignorecase)', function () {
const map = new ResourceMap<any>(true);
......@@ -412,22 +440,14 @@ suite('Map', () => {
map.set(fileA, 'true');
assert.equal(map.get(fileA), 'true');
if (!isLinux) {
assert.equal(map.get(fileAUpper), 'true');
} else {
assert.ok(!map.get(fileAUpper));
}
assert.equal(map.get(fileAUpper), 'true');
assert.ok(!map.get(fileB));
map.set(fileAUpper, 'false');
assert.equal(map.get(fileAUpper), 'false');
if (!isLinux) {
assert.equal(map.get(fileA), 'false');
} else {
assert.equal(map.get(fileA), 'true');
}
assert.equal(map.get(fileA), 'false');
const windowsFile = URI.file('c:\\test with %25\\c#code');
const uncFile = URI.file('\\\\shäres\\path\\c#\\plugin.json');
......
......@@ -187,9 +187,11 @@ suite('Paths', () => {
assert.ok(!paths.isValidBasename(''));
assert.ok(paths.isValidBasename('test.txt'));
assert.ok(!paths.isValidBasename('/test.txt'));
assert.ok(!paths.isValidBasename('\\test.txt'));
if (platform.isWindows) {
if (!platform.isWindows) {
assert.ok(paths.isValidBasename('\\test.txt'));
} else if (platform.isWindows) {
assert.ok(!paths.isValidBasename('\\test.txt'));
assert.ok(!paths.isValidBasename('aux'));
assert.ok(!paths.isValidBasename('Aux'));
assert.ok(!paths.isValidBasename('LPT0'));
......
......@@ -5,7 +5,7 @@
'use strict';
import 'vs/css!./suggest';
import 'vs/css!./media/suggest';
import * as nls from 'vs/nls';
import { createMatches } from 'vs/base/common/filters';
import * as strings from 'vs/base/common/strings';
......
......@@ -43,7 +43,7 @@ export class MainThreadOutputService extends MainThreadOutputServiceShape {
}
private _getChannel(channelId: string, label: string): IOutputChannel {
if (Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).getChannels().every(channel => channel.id !== channelId)) {
if (!Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).getChannel(channelId)) {
Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).registerChannel(channelId, label);
}
......
......@@ -677,10 +677,21 @@ export class ReportIssueAction extends Action {
super(id, label);
}
private _optimisticIsPure(): TPromise<boolean> {
let isPure = true;
let integrityPromise = this.integrityService.isPure().then(res => {
isPure = res.isPure;
});
return TPromise.any([TPromise.timeout(100), integrityPromise]).then(() => {
return isPure;
});
}
public run(): TPromise<boolean> {
return this.integrityService.isPure().then(res => {
return this._optimisticIsPure().then(isPure => {
return this.extensionManagementService.getInstalled(LocalExtensionType.User).then(extensions => {
const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, res.isPure, extensions);
const issueUrl = this.generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date, isPure, extensions);
window.open(issueUrl);
......
......@@ -206,14 +206,16 @@ suite('Files - View Model', () => {
assert(validateFileName(s, ' ') !== null);
assert(validateFileName(s, 'Read Me') === null, 'name containing space');
assert(validateFileName(s, 'foo/bar') !== null);
assert(validateFileName(s, 'foo\\bar') !== null);
if (isWindows) {
assert(validateFileName(s, 'foo\\bar') !== null);
assert(validateFileName(s, 'foo:bar') !== null);
assert(validateFileName(s, 'foo*bar') !== null);
assert(validateFileName(s, 'foo?bar') !== null);
assert(validateFileName(s, 'foo<bar') !== null);
assert(validateFileName(s, 'foo>bar') !== null);
assert(validateFileName(s, 'foo|bar') !== null);
} else {
assert(validateFileName(s, 'foo\\bar') === null);
}
assert(validateFileName(s, 'alles.klar') !== null);
......
......@@ -107,9 +107,10 @@ export class SwitchOutputActionItem extends SelectActionItem {
action: IAction,
@IOutputService private outputService: IOutputService
) {
super(null, action, SwitchOutputActionItem.getChannelLabels(outputService), Math.max(0, SwitchOutputActionItem.getChannelLabels(outputService).indexOf(outputService.getActiveChannel().label)));
this.toDispose.push(this.outputService.onOutputChannel(this.onOutputChannel, this));
this.toDispose.push(this.outputService.onActiveOutputChannel(this.onOutputChannel, this));
super(null, action, [], 0);
this.toDispose.push(this.outputService.onOutputChannel(() => this.setOptions(this.getOptions(), this.getSelected(undefined))));
this.toDispose.push(this.outputService.onActiveOutputChannel(activeChannelId => this.setOptions(this.getOptions(), this.getSelected(activeChannelId))));
this.setOptions(this.getOptions(), this.getSelected(this.outputService.getActiveChannel().id));
}
protected getActionContext(option: string): string {
......@@ -118,16 +119,15 @@ export class SwitchOutputActionItem extends SelectActionItem {
return channel ? channel.id : option;
}
private onOutputChannel(): void {
let channels = SwitchOutputActionItem.getChannelLabels(this.outputService);
let selected = Math.max(0, channels.indexOf(this.outputService.getActiveChannel().label));
this.setOptions(channels, selected);
private getOptions(): string[] {
return this.outputService.getChannels().map(c => c.label);
}
private static getChannelLabels(outputService: IOutputService): string[] {
const contributedChannels = outputService.getChannels().map(channelData => channelData.label);
private getSelected(outputId: string): number {
if (!outputId) {
return undefined;
}
return contributedChannels.sort(); // sort by name
return Math.max(0, this.outputService.getChannels().map(c => c.id).indexOf(outputId));
}
}
......@@ -6,6 +6,7 @@
import { TPromise } from 'vs/base/common/winjs.base';
import strings = require('vs/base/common/strings');
import Event, { Emitter } from 'vs/base/common/event';
import { binarySearch } from 'vs/base/common/arrays';
import URI from 'vs/base/common/uri';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IEditor } from 'vs/platform/editor/common/editor';
......@@ -13,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { Registry } from 'vs/platform/platform';
import { EditorOptions } from 'vs/workbench/common/editor';
import { IOutputChannelIdentifier, OutputEditors, IOutputEvent, IOutputChannel, IOutputService, Extensions, OUTPUT_PANEL_ID, IOutputChannelRegistry, MAX_OUTPUT_LENGTH, OUTPUT_SCHEME, OUTPUT_MIME } from 'vs/workbench/parts/output/common/output';
import { IOutputChannelIdentifier, OutputEditors, IOutputEvent, IOutputChannel, IOutputService, IOutputDelta, Extensions, OUTPUT_PANEL_ID, IOutputChannelRegistry, MAX_OUTPUT_LENGTH, OUTPUT_SCHEME, OUTPUT_MIME } from 'vs/workbench/parts/output/common/output';
import { OutputPanel } from 'vs/workbench/parts/output/browser/outputPanel';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IModelService } from 'vs/editor/common/services/modelService';
......@@ -28,11 +29,61 @@ import { Position } from 'vs/editor/common/core/position';
const OUTPUT_ACTIVE_CHANNEL_KEY = 'output.activechannel';
class BufferedContent {
private data: string[] = [];
private dataIds: number[] = [];
private idPool = 0;
private length = 0;
public append(content: string): void {
this.data.push(content);
this.dataIds.push(++this.idPool);
this.length += content.length;
this.trim();
}
public clear(): void {
this.data.length = 0;
this.dataIds.length = 0;
this.length = 0;
}
private trim(): void {
if (this.length < MAX_OUTPUT_LENGTH * 1.5) {
return;
}
while (this.length > MAX_OUTPUT_LENGTH && this.data.length) {
this.dataIds.shift();
const removed = this.data.shift();
this.length -= removed.length;
}
}
public value(previousDelta?: IOutputDelta): IOutputDelta {
let idx = -1;
if (previousDelta) {
idx = binarySearch(this.dataIds, previousDelta.id, (a, b) => a - b);
}
const id = this.idPool;
if (idx >= 0) {
const value = strings.removeAnsiEscapeCodes(this.data.slice(idx).join(''));
return { value, id, append: true };
} else {
const value = strings.removeAnsiEscapeCodes(this.data.join(''));
return { value, id };
}
}
}
export class OutputService implements IOutputService {
public _serviceBrand: any;
private receivedOutput: Map<string, string>;
private receivedOutput: Map<string, BufferedContent> = new Map<string, BufferedContent>();
private channels: Map<string, IOutputChannel> = new Map<string, IOutputChannel>();
private activeChannelId: string;
......@@ -56,8 +107,6 @@ export class OutputService implements IOutputService {
this._onOutputChannel = new Emitter<string>();
this._onActiveOutputChannel = new Emitter<string>();
this.receivedOutput = new Map<string, string>();
const channels = this.getChannels();
this.activeChannelId = this.storageService.get(OUTPUT_ACTIVE_CHANNEL_KEY, StorageScope.WORKSPACE, channels && channels.length > 0 ? channels[0].id : null);
......@@ -82,26 +131,30 @@ export class OutputService implements IOutputService {
}
public getChannel(id: string): IOutputChannel {
const channelData = this.getChannels().filter(channelData => channelData.id === id).pop();
const self = this;
return {
id,
label: channelData ? channelData.label : id,
get output() {
return self.getOutput(id);
},
get scrollLock() {
return self._outputContentProvider.scrollLock(id);
},
set scrollLock(value: boolean) {
self._outputContentProvider.setScrollLock(id, value);
},
append: (output: string) => this.append(id, output),
show: (preserveFocus: boolean) => this.showOutput(id, preserveFocus),
clear: () => this.clearOutput(id),
dispose: () => this.removeOutput(id)
};
if (!this.channels.has(id)) {
const channelData = Registry.as<IOutputChannelRegistry>(Extensions.OutputChannels).getChannel(id);
const self = this;
this.channels.set(id, {
id,
label: channelData ? channelData.label : id,
getOutput(before?: IOutputDelta) {
return self.getOutput(id, before);
},
get scrollLock() {
return self._outputContentProvider.scrollLock(id);
},
set scrollLock(value: boolean) {
self._outputContentProvider.setScrollLock(id, value);
},
append: (output: string) => this.append(id, output),
show: (preserveFocus: boolean) => this.showOutput(id, preserveFocus),
clear: () => this.clearOutput(id),
dispose: () => this.removeOutput(id)
});
}
return this.channels.get(id);
}
public getChannels(): IOutputChannelIdentifier[] {
......@@ -112,34 +165,37 @@ export class OutputService implements IOutputService {
// Initialize
if (!this.receivedOutput.has(channelId)) {
this.receivedOutput.set(channelId, '');
this.receivedOutput.set(channelId, new BufferedContent());
this._onOutputChannel.fire(channelId); // emit event that we have a new channel
}
// Sanitize
output = strings.removeAnsiEscapeCodes(output);
// Store
if (output) {
this.receivedOutput.set(channelId, strings.appendWithLimit(this.receivedOutput.get(channelId), output, MAX_OUTPUT_LENGTH));
const channel = this.receivedOutput.get(channelId);
channel.append(output);
}
this._onOutput.fire({ output: output, channelId: channelId });
this._onOutput.fire({ channelId: channelId, isClear: false });
}
public getActiveChannel(): IOutputChannel {
return this.getChannel(this.activeChannelId);
}
private getOutput(channelId: string): string {
return this.receivedOutput.get(channelId) || '';
private getOutput(channelId: string, before: IOutputDelta): IOutputDelta {
if (this.receivedOutput.has(channelId)) {
return this.receivedOutput.get(channelId).value(before);
}
return undefined;
}
private clearOutput(channelId: string): void {
this.receivedOutput.set(channelId, '');
this._onOutput.fire({ channelId: channelId, output: null /* indicator to clear output */ });
if (this.receivedOutput.has(channelId)) {
this.receivedOutput.get(channelId).clear();
this._onOutput.fire({ channelId: channelId, isClear: true });
}
}
private removeOutput(channelId: string): void {
......@@ -179,10 +235,9 @@ class OutputContentProvider implements ITextModelContentProvider {
private static OUTPUT_DELAY = 300;
private bufferedOutput: { [channel: string]: string; };
private bufferedOutput = new Map<string, IOutputDelta>();
private appendOutputScheduler: { [channel: string]: RunOnceScheduler; };
private channelIdsWithScrollLock: Set<string> = new Set();
private toDispose: IDisposable[];
constructor(
......@@ -191,7 +246,6 @@ class OutputContentProvider implements ITextModelContentProvider {
@IModeService private modeService: IModeService,
@IPanelService private panelService: IPanelService
) {
this.bufferedOutput = Object.create(null);
this.appendOutputScheduler = Object.create(null);
this.toDispose = [];
......@@ -215,15 +269,10 @@ class OutputContentProvider implements ITextModelContentProvider {
}
// Append to model
if (e.output) {
this.bufferedOutput[e.channelId] = strings.appendWithLimit(this.bufferedOutput[e.channelId] || '', e.output, MAX_OUTPUT_LENGTH);
this.scheduleOutputAppend(e.channelId);
}
// Clear from model
else if (e.output === null) {
this.bufferedOutput[e.channelId] = '';
if (e.isClear) {
model.setValue('');
} else {
this.scheduleOutputAppend(e.channelId);
}
}
......@@ -236,10 +285,6 @@ class OutputContentProvider implements ITextModelContentProvider {
return; // only if the output channel is visible
}
if (!this.bufferedOutput[channel]) {
return; // only if we have any output to show
}
let scheduler = this.appendOutputScheduler[channel];
if (!scheduler) {
scheduler = new RunOnceScheduler(() => {
......@@ -274,15 +319,17 @@ class OutputContentProvider implements ITextModelContentProvider {
return; // only react if we have a known model
}
const bufferedOutput = this.bufferedOutput[channel];
this.bufferedOutput[channel] = '';
if (!bufferedOutput) {
return; // return if nothing to append
const bufferedOutput = this.bufferedOutput.get(channel);
const newOutput = this.outputService.getChannel(channel).getOutput(bufferedOutput);
if (!newOutput) {
model.setValue('');
return;
}
this.bufferedOutput.set(channel, newOutput);
// just fill in the full (trimmed) output if we exceed max length
if (model.getValueLength() + bufferedOutput.length > MAX_OUTPUT_LENGTH) {
model.setValue(this.outputService.getChannel(channel).output);
if (!newOutput.append) {
model.setValue(newOutput.value);
}
// otherwise append
......@@ -290,7 +337,7 @@ class OutputContentProvider implements ITextModelContentProvider {
const lastLine = model.getLineCount();
const lastLineMaxColumn = model.getLineMaxColumn(lastLine);
model.applyEdits([EditOperation.insert(new Position(lastLine, lastLineMaxColumn), bufferedOutput)]);
model.applyEdits([EditOperation.insert(new Position(lastLine, lastLineMaxColumn), newOutput.value)]);
}
if (!this.channelIdsWithScrollLock.has(channel)) {
......@@ -319,7 +366,8 @@ class OutputContentProvider implements ITextModelContentProvider {
}
public provideTextContent(resource: URI): TPromise<IModel> {
const content = this.outputService.getChannel(resource.fsPath).output;
const output = this.outputService.getChannel(resource.fsPath).getOutput();
const content = output ? output.value : '';
let codeEditorModel = this.modelService.getModel(resource);
if (!codeEditorModel) {
......
......@@ -48,8 +48,8 @@ export const CONTEXT_IN_OUTPUT = new RawContextKey<boolean>('inOutput', false);
* The output event informs when new output got received.
*/
export interface IOutputEvent {
output: string;
channelId?: string;
channelId: string;
isClear: boolean;
}
export const IOutputService = createDecorator<IOutputService>(OUTPUT_SERVICE_ID);
......@@ -93,6 +93,12 @@ export interface IOutputService {
onActiveOutputChannel: Event<string>;
}
export interface IOutputDelta {
readonly value: string;
readonly id: number;
readonly append?: boolean;
}
export interface IOutputChannel {
/**
......@@ -105,11 +111,6 @@ export interface IOutputChannel {
*/
label: string;
/**
* Returns the received output content.
*/
output: string;
/**
* Returns the value indicating whether the channel has scroll locked.
*/
......@@ -120,6 +121,12 @@ export interface IOutputChannel {
*/
append(output: string): void;
/**
* Returns the received output content.
* If a delta is passed, returns only the content that came after the passed delta.
*/
getOutput(previousDelta?: IOutputDelta): IOutputDelta;
/**
* Opens the output for this channel.
*/
......@@ -153,6 +160,11 @@ export interface IOutputChannelRegistry {
*/
getChannels(): IOutputChannelIdentifier[];
/**
* Returns the channel with the passed id.
*/
getChannel(id: string): IOutputChannelIdentifier;
/**
* Remove the output channel with the passed id.
*/
......@@ -160,24 +172,26 @@ export interface IOutputChannelRegistry {
}
class OutputChannelRegistry implements IOutputChannelRegistry {
private channels: IOutputChannelIdentifier[];
constructor() {
this.channels = [];
}
private channels = new Map<string, IOutputChannelIdentifier>();
public registerChannel(id: string, label: string): void {
if (this.channels.every(channel => channel.id !== id)) {
this.channels.push({ id, label });
if (!this.channels.has(id)) {
this.channels.set(id, { id, label });
}
}
public getChannels(): IOutputChannelIdentifier[] {
return this.channels;
const result: IOutputChannelIdentifier[] = [];
this.channels.forEach(value => result.push(value));
return result;
}
public getChannel(id: string): IOutputChannelIdentifier {
return this.channels.get(id);
}
public removeChannel(id: string): void {
this.channels = this.channels.filter(channel => channel.id !== id);
this.channels.delete(id);
}
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/workbench/parts/search/browser/search.contribution'; // load contributions
import * as assert from 'assert';
import * as fs from 'fs';
import { WorkspaceContextService, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { createSyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { ISearchService, IQueryOptions } from 'vs/platform/search/common/search';
import { ITelemetryService, ITelemetryInfo, ITelemetryExperiments } from 'vs/platform/telemetry/common/telemetry';
import { defaultExperiments } from 'vs/platform/telemetry/common/telemetryUtils';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import * as minimist from 'minimist';
import * as path from 'path';
import { SearchService } from 'vs/workbench/services/search/node/searchService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { TestEnvironmentService, TestEditorService, TestEditorGroupService } from 'vs/workbench/test/workbenchTestServices';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { TPromise } from 'vs/base/common/winjs.base';
import URI from 'vs/base/common/uri';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { SimpleConfigurationService } from 'vs/editor/browser/standalone/simpleServices';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
import { IModelService } from 'vs/editor/common/services/modelService';
import { SearchModel } from 'vs/workbench/parts/search/common/searchModel';
import { QueryBuilder } from 'vs/workbench/parts/search/common/searchQuery';
import Event, * as event from 'vs/base/common/event';
declare var __dirname: string;
// Checkout sources to run against:
// git clone --separate-git-dir=testGit --no-checkout --single-branch https://chromium.googlesource.com/chromium/src testWorkspace
// cd testWorkspace; git checkout 39a7f93d67f7
// Run from repository root folder with (test.bat on Windows): ./scripts/test.sh --grep TextSearch.performance --timeout 500000 --testWorkspace <path>
suite('TextSearch performance', () => {
test('Measure', () => {
if (process.env['VSCODE_PID']) {
return undefined; // TODO@Rob find out why test fails when run from within VS Code
}
const n = 3;
const argv = minimist(process.argv);
const testWorkspaceArg = argv['testWorkspace'];
const testWorkspacePath = testWorkspaceArg ? path.resolve(testWorkspaceArg) : __dirname;
if (!fs.existsSync(testWorkspacePath)) {
throw new Error(`--testWorkspace doesn't exist`);
}
const telemetryService = new TestTelemetryService();
const configurationService = new SimpleConfigurationService();
const instantiationService = new InstantiationService(new ServiceCollection(
[ITelemetryService, telemetryService],
[IConfigurationService, new SimpleConfigurationService()],
[IModelService, new ModelServiceImpl(null, configurationService)],
[IWorkspaceContextService, new WorkspaceContextService({ resource: URI.file(testWorkspacePath) })],
[IWorkbenchEditorService, new TestEditorService()],
[IEditorGroupService, new TestEditorGroupService()],
[IEnvironmentService, TestEnvironmentService],
[IUntitledEditorService, createSyncDescriptor(UntitledEditorService)],
[ISearchService, createSyncDescriptor(SearchService)]
));
let queryOptions: IQueryOptions = {
folderResources: [URI.file(testWorkspacePath)],
maxResults: 2048
};
const searchModel: SearchModel = instantiationService.createInstance(SearchModel);
function runSearch(): TPromise<any> {
const queryBuilder: QueryBuilder = instantiationService.createInstance(QueryBuilder);
const query = queryBuilder.text({ pattern: 'static_library(' }, queryOptions);
// Wait for the 'searchResultsFinished' event, which is fired after the search() promise is resolved
const onSearchResultsFinished = event.filterEvent(telemetryService.eventLogged, e => e.name === 'searchResultsFinished');
event.once(onSearchResultsFinished)(onComplete);
function onComplete(): void {
try {
const allEvents = telemetryService.events.map(e => JSON.stringify(e)).join('\n');
assert.equal(telemetryService.events.length, 3, 'Expected 3 telemetry events, got:\n' + allEvents);
const [firstRenderEvent, resultsShownEvent, resultsFinishedEvent] = telemetryService.events;
assert.equal(firstRenderEvent.name, 'searchResultsFirstRender');
assert.equal(resultsShownEvent.name, 'searchResultsShown');
assert.equal(resultsFinishedEvent.name, 'searchResultsFinished');
telemetryService.events = [];
resolve(resultsFinishedEvent);
} catch (e) {
// Fail the runSearch() promise
error(e);
}
}
let resolve;
let error;
return new TPromise((_resolve, _error) => {
resolve = _resolve;
error = _error;
// Don't wait on this promise, we're waiting on the event fired above
searchModel.search(query).then(
null,
_error);
});
}
const finishedEvents = [];
return runSearch() // Warm-up first
.then(() => {
if (testWorkspaceArg) { // Don't measure by default
let i = n;
return (function iterate() {
if (!i--) {
return;
}
return runSearch()
.then((resultsFinishedEvent: any) => {
console.log(`Iteration ${n - i}: ${resultsFinishedEvent.data.duration / 1000}s`);
finishedEvents.push(resultsFinishedEvent);
return iterate();
});
})().then(() => {
const totalTime = finishedEvents.reduce((sum, e) => sum + e.data.duration, 0);
console.log(`Avg duration: ${totalTime / n / 1000}s`);
});
}
});
});
});
class TestTelemetryService implements ITelemetryService {
public _serviceBrand: any;
public isOptedIn = true;
public events: any[] = [];
private emitter = new event.Emitter<any>();
public get eventLogged(): Event<any> {
return this.emitter.event;
}
public publicLog(eventName: string, data?: any): TPromise<void> {
const event = { name: eventName, data: data };
this.events.push(event);
this.emitter.fire(event);
return TPromise.as<void>(null);
}
public getTelemetryInfo(): TPromise<ITelemetryInfo> {
return TPromise.as({
instanceId: 'someValue.instanceId',
sessionId: 'someValue.sessionId',
machineId: 'someValue.machineId'
});
}
public getExperiments(): ITelemetryExperiments {
return defaultExperiments;
}
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册