diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 8ad715681ec..1afb6de2cf2 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -859,9 +859,8 @@ namespace FourSlash { } } - public verifyReferencesOf({fileName, start}: Range, references: Range[]) { - this.openFile(fileName); - this.goToPosition(start); + public verifyReferencesOf(range: Range, references: Range[]) { + this.goToRangeStart(range); this.verifyReferencesAre(references); } @@ -1669,6 +1668,11 @@ namespace FourSlash { this.goToPosition(len); } + private goToRangeStart({fileName, start}: Range) { + this.openFile(fileName); + this.goToPosition(start); + } + public goToTypeDefinition(definitionIndex: number) { const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (!definitions || !definitions.length) { @@ -2361,40 +2365,45 @@ namespace FourSlash { return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch); } - public verifyDocumentHighlightsAtPositionListContains(fileName: string, start: number, end: number, fileNamesToSearch: string[], kind?: string) { - const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); + public verifyRangesWithSameTextAreDocumentHighlights() { + this.rangesByText().forEach(ranges => this.verifyRangesAreDocumentHighlights(ranges)); + } - if (!documentHighlights || documentHighlights.length === 0) { - this.raiseError("verifyDocumentHighlightsAtPositionListContains failed - found 0 highlights, expected at least one."); + public verifyRangesAreDocumentHighlights(ranges?: Range[]) { + ranges = ranges || this.getRanges(); + const fileNames = unique(ranges, range => range.fileName); + for (const range of ranges) { + this.goToRangeStart(range); + this.verifyDocumentHighlights(ranges, fileNames); } + } - for (const documentHighlight of documentHighlights) { - if (documentHighlight.fileName === fileName) { - const { highlightSpans } = documentHighlight; + private verifyDocumentHighlights(expectedRanges: Range[], fileNames: string[] = [this.activeFile.fileName]) { + const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNames) || []; - for (const highlight of highlightSpans) { - if (highlight && highlight.textSpan.start === start && ts.textSpanEnd(highlight.textSpan) === end) { - if (typeof kind !== "undefined" && highlight.kind !== kind) { - this.raiseError(`verifyDocumentHighlightsAtPositionListContains failed - item "kind" value does not match, actual: ${highlight.kind}, expected: ${kind}.`); - } - return; - } - } + for (const dh of documentHighlights) { + if (fileNames.indexOf(dh.fileName) === -1) { + this.raiseError(`verifyDocumentHighlights failed - got highlights in unexpected file name ${dh.fileName}`); } } - const missingItem = { fileName: fileName, start: start, end: end, kind: kind }; - this.raiseError(`verifyDocumentHighlightsAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(documentHighlights)})`); - } + for (const fileName of fileNames) { + const expectedRangesInFile = expectedRanges.filter(r => r.fileName === fileName); + const highlights = ts.find(documentHighlights, dh => dh.fileName === fileName); + if (!highlights) { + this.raiseError(`verifyDocumentHighlights failed - found no highlights in ${fileName}`); + } + const spansInFile = highlights.highlightSpans.sort((s1, s2) => s1.textSpan.start - s2.textSpan.start); - public verifyDocumentHighlightsAtPositionListCount(expectedCount: number, fileNamesToSearch: string[]) { - const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); - const actualCount = documentHighlights - ? documentHighlights.reduce((currentCount, { highlightSpans }) => currentCount + highlightSpans.length, 0) - : 0; + if (expectedRangesInFile.length !== spansInFile.length) { + this.raiseError(`verifyDocumentHighlights failed - In ${fileName}, expected ${expectedRangesInFile.length} highlights, got ${spansInFile.length}`); + } - if (expectedCount !== actualCount) { - this.raiseError("verifyDocumentHighlightsAtPositionListCount failed - actual: " + actualCount + ", expected:" + expectedCount); + ts.zipWith(expectedRangesInFile, spansInFile, (expectedRange, span) => { + if (span.textSpan.start !== expectedRange.start || ts.textSpanEnd(span.textSpan) !== expectedRange.end) { + this.raiseError(`verifyDocumentHighlights failed - span does not match, actual: ${JSON.stringify(span.textSpan)}, expected: ${expectedRange.start}--${expectedRange.end}`); + } + }); } } @@ -3021,6 +3030,16 @@ ${code} function stringify(data: any, replacer?: (key: string, value: any) => any): string { return JSON.stringify(data, replacer, 2); } + + /** Collects an array of unique outputs. */ + function unique(inputs: T[], getOutput: (t: T) => string): string[] { + const set = ts.createMap(); + for (const input of inputs) { + const out = getOutput(input); + set.set(out, true); + } + return ts.arrayFrom(set.keys()); + } } namespace FourSlashInterface { @@ -3413,12 +3432,12 @@ namespace FourSlashInterface { this.state.verifyOccurrencesAtPositionListCount(expectedCount); } - public documentHighlightsAtPositionContains(range: FourSlash.Range, fileNamesToSearch: string[], kind?: string) { - this.state.verifyDocumentHighlightsAtPositionListContains(range.fileName, range.start, range.end, fileNamesToSearch, kind); + public rangesAreDocumentHighlights(ranges?: FourSlash.Range[]) { + this.state.verifyRangesAreDocumentHighlights(ranges); } - public documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[]) { - this.state.verifyDocumentHighlightsAtPositionListCount(expectedCount, fileNamesToSearch); + public rangesWithSameTextAreDocumentHighlights() { + this.state.verifyRangesWithSameTextAreDocumentHighlights(); } public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string) { diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts index 23f6445a004..0c07edea506 100644 --- a/tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties1.ts @@ -2,12 +2,8 @@ // @Filename: file1.ts //// interface interface1 extends interface1 { -//// /*1*/doStuff(): void; -//// /*2*/propName: string; +//// [|doStuff|](): void; +//// [|propName|]: string; //// } -let markers = test.markers() -for (let marker of markers) { - goTo.position(marker.position); - verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); -} +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts index d4aadf96ed6..3327c36b760 100644 --- a/tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties2.ts @@ -2,12 +2,8 @@ // @Filename: file1.ts //// class class1 extends class1 { -//// /*1*/doStuff() { } -//// /*2*/propName: string; +//// [|doStuff|]() { } +//// [|propName|]: string; //// } -let markers = test.markers() -for (let marker of markers) { - goTo.position(marker.position); - verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); -} \ No newline at end of file +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts index 5e94bb387cd..11625df1442 100644 --- a/tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties3.ts @@ -2,16 +2,12 @@ // @Filename: file1.ts //// interface interface1 extends interface1 { -//// /*1*/doStuff(): void; -//// /*2*/propName: string; +//// [|doStuff|](): void; +//// [|propName|]: string; //// } //// //// var v: interface1; -//// v./*3*/propName; -//// v./*4*/doStuff(); +//// v.[|propName|]; +//// v.[|doStuff|](); -let markers = test.markers() -for (let marker of markers) { - goTo.position(marker.position); - verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); -} +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts index 50f459ebfdb..1c78233554a 100644 --- a/tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties4.ts @@ -2,16 +2,12 @@ // @Filename: file1.ts //// class class1 extends class1 { -//// /*1*/doStuff() { } -//// /*2*/propName: string; +//// [|doStuff|]() { } +//// [|propName|]: string; //// } //// //// var c: class1; -//// c./*3*/doStuff(); -//// c./*4*/propName; +//// c.[|doStuff|](); +//// c.[|propName|]; -let markers = test.markers() -for (let marker of markers) { - goTo.position(marker.position); - verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); -} +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts index b5f4cbb00a7..4fdf4a689ac 100644 --- a/tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties5.ts @@ -2,29 +2,16 @@ // @Filename: file1.ts //// interface C extends D { -//// /*0*/prop0: string; -//// /*1*/prop1: number; +//// [|prop0|]: string; +//// [|prop1|]: number; //// } -//// +//// //// interface D extends C { -//// /*2*/prop0: string; -//// /*3*/prop1: number; +//// [|prop0|]: string; +//// [|prop1|]: number; //// } -//// +//// //// var d: D; -//// d./*4*/prop1; +//// d.[|prop1|]; -goTo.marker("0"); -verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); - -goTo.marker("1"); -verify.documentHighlightsAtPositionCount(3, ["file1.ts"]); - -goTo.marker("2"); -verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); - -goTo.marker("3"); -verify.documentHighlightsAtPositionCount(3, ["file1.ts"]); - -goTo.marker("4"); -verify.documentHighlightsAtPositionCount(3, ["file1.ts"]); \ No newline at end of file +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts b/tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts index 8f1089e567d..6eb7ae16723 100644 --- a/tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts +++ b/tests/cases/fourslash/documentHighlightAtInheritedProperties6.ts @@ -2,29 +2,20 @@ // @Filename: file1.ts //// class C extends D { -//// /*0*/prop0: string; -//// /*1*/prop1: string; +//// [|prop0|]: string; +//// [|prop1|]: string; //// } -//// +//// //// class D extends C { -//// /*2*/prop0: string; -//// /*3*/prop1: string; +//// [|prop0|]: string; +//// [|prop1|]: string; //// } -//// +//// //// var d: D; -//// d./*4*/prop1; +//// d.[|prop1|]; -goTo.marker("0"); -verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); - -goTo.marker("1"); -verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); - -goTo.marker("2"); -verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); - -goTo.marker("3"); -verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); - -goTo.marker("4"); -verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); \ No newline at end of file +const [Cprop0, Cprop1, Dprop0, Dprop1, prop1Use] = test.ranges(); +verify.rangesAreDocumentHighlights([Cprop0]); +verify.rangesAreDocumentHighlights([Dprop0]); +verify.rangesAreDocumentHighlights([Cprop1]); +verify.rangesAreDocumentHighlights([Dprop1, prop1Use]); diff --git a/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration1.ts b/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration1.ts index aeccd252fe9..219ea427b9c 100644 --- a/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration1.ts +++ b/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration1.ts @@ -2,23 +2,19 @@ // @Filename: file1.ts //// class Foo { -//// constructor(private /*0*/privateParam: number, -//// public /*1*/publicParam: string, -//// protected /*2*/protectedParam: boolean) { -//// -//// let localPrivate = /*3*/privateParam; -//// this./*4*/privateParam += 10; -//// -//// let localPublic = /*5*/publicParam; -//// this./*6*/publicParam += " Hello!"; -//// -//// let localProtected = /*7*/protectedParam; -//// this./*8*/protectedParam = false; +//// constructor(private [|privateParam|]: number, +//// public [|publicParam|]: string, +//// protected [|protectedParam|]: boolean) { +//// +//// let localPrivate = [|privateParam|]; +//// this.[|privateParam|] += 10; +//// +//// let localPublic = [|publicParam|]; +//// this.[|publicParam|] += " Hello!"; +//// +//// let localProtected = [|protectedParam|]; +//// this.[|protectedParam|] = false; //// } //// } -let markers = test.markers() -for (let marker of markers) { - goTo.position(marker.position); - verify.documentHighlightsAtPositionCount(3, ["file1.ts"]); -} \ No newline at end of file +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration2.ts b/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration2.ts index f5d6764205b..199f59fc8a3 100644 --- a/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration2.ts +++ b/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration2.ts @@ -2,23 +2,20 @@ // @Filename: file1.ts //// class Foo { -//// constructor(private {/*0*/privateParam}: number, -//// public {/*1*/publicParam}: string, -//// protected {/*2*/protectedParam}: boolean) { -//// -//// let localPrivate = /*3*/privateParam; -//// this.privateParam += 10; // this is not valid syntax -//// -//// let localPublic = /*4*/publicParam; -//// this.publicParam += " Hello!"; // this is not valid syntax -//// -//// let localProtected = /*5*/protectedParam; -//// this.protectedParam = false; // this is not valid syntax +//// // This is not valid syntax: parameter property can't be binding pattern +//// constructor(private {[|privateParam|]}: number, +//// public {[|publicParam|]}: string, +//// protected {[|protectedParam|]}: boolean) { +//// +//// let localPrivate = [|privateParam|]; +//// this.privateParam += 10; +//// +//// let localPublic = [|publicParam|]; +//// this.publicParam += " Hello!"; +//// +//// let localProtected = [|protectedParam|]; +//// this.protectedParam = false; //// } //// } -let markers = test.markers() -for (let marker of markers) { - goTo.position(marker.position); - verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); -} \ No newline at end of file +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration3.ts b/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration3.ts index 958e3bb45c9..7bcd44a5425 100644 --- a/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration3.ts +++ b/tests/cases/fourslash/documentHighlightAtParameterPropertyDeclaration3.ts @@ -2,23 +2,20 @@ // @Filename: file1.ts //// class Foo { -//// constructor(private [/*0*/privateParam]: number, -//// public [/*1*/publicParam]: string, -//// protected [/*2*/protectedParam]: boolean) { -//// -//// let localPrivate = /*3*/privateParam; -//// this.privateParam += 10; // this is not valid syntax -//// -//// let localPublic = /*4*/publicParam; -//// this.publicParam += " Hello!"; // this is not valid syntax -//// -//// let localProtected = /*5*/protectedParam; -//// this.protectedParam = false; // this is not valid syntax +//// // This is not valid syntax: parameter property can't be binding pattern +//// constructor(private [[|privateParam|]]: number, +//// public [[|publicParam|]]: string, +//// protected [[|protectedParam|]]: boolean) { +//// +//// let localPrivate = [|privateParam|]; +//// this.privateParam += 10; +//// +//// let localPublic = [|publicParam|]; +//// this.publicParam += " Hello!"; +//// +//// let localProtected = [|protectedParam|]; +//// this.protectedParam = false; //// } //// } -let markers = test.markers() -for (let marker of markers) { - goTo.position(marker.position); - verify.documentHighlightsAtPositionCount(2, ["file1.ts"]); -} \ No newline at end of file +verify.rangesWithSameTextAreDocumentHighlights(); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index ab67abc1bb6..ed09fcd2c92 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -229,8 +229,8 @@ declare namespace FourSlashInterface { navigationItemsListContains(name: string, kind: string, searchValue: string, matchKind: string, fileName?: string, parentName?: string): void; occurrencesAtPositionContains(range: Range, isWriteAccess?: boolean): void; occurrencesAtPositionCount(expectedCount: number): void; - documentHighlightsAtPositionContains(range: Range, fileNamesToSearch: string[], kind?: string): void; - documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[]): void; + rangesAreDocumentHighlights(ranges?: Range[]): void; + rangesWithSameTextAreDocumentHighlights(): void; completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string): void; /** * This method *requires* a contiguous, complete, and ordered stream of classifications for a file. diff --git a/tests/cases/fourslash/getPropertySymbolsFromBaseTypesDoesntCrash.ts b/tests/cases/fourslash/getPropertySymbolsFromBaseTypesDoesntCrash.ts index 0c89de63a43..e141a257f2e 100644 --- a/tests/cases/fourslash/getPropertySymbolsFromBaseTypesDoesntCrash.ts +++ b/tests/cases/fourslash/getPropertySymbolsFromBaseTypesDoesntCrash.ts @@ -2,8 +2,7 @@ // @Filename: file1.ts //// class ClassA implements IInterface { -//// private /*1*/value: number; +//// private [|value|]: number; //// } -goTo.marker("1"); -verify.documentHighlightsAtPositionCount(1, ["file1.ts"]); \ No newline at end of file +verify.rangesAreDocumentHighlights(); diff --git a/tests/cases/fourslash/server/documentHighlights01.ts b/tests/cases/fourslash/server/documentHighlights01.ts index d4be88f9357..0acfbcb9d11 100644 --- a/tests/cases/fourslash/server/documentHighlights01.ts +++ b/tests/cases/fourslash/server/documentHighlights01.ts @@ -5,14 +5,4 @@ //// [|f|]([|f|]); ////} -let ranges = test.ranges(); - -for (let r of ranges) { - goTo.position(r.start); - verify.documentHighlightsAtPositionCount(ranges.length, ["a.ts"]); - - for (let range of ranges) { - verify.documentHighlightsAtPositionContains(range, ["a.ts"]); - } -} - +verify.rangesAreDocumentHighlights(); diff --git a/tests/cases/fourslash/server/documentHighlights02.ts b/tests/cases/fourslash/server/documentHighlights02.ts index 357f82e9c2d..3fd71d4a65d 100644 --- a/tests/cases/fourslash/server/documentHighlights02.ts +++ b/tests/cases/fourslash/server/documentHighlights02.ts @@ -8,28 +8,10 @@ // @Filename: b.ts /////// -////foo(); +////[|foo|](); // open two files goTo.file("a.ts"); goTo.file("b.ts"); -let ranges = test.ranges(); - -for (let i = 0; i < ranges.length; ++i) { - let r = ranges[i]; - - if (i < 2) { - goTo.file("a.ts"); - } - else { - goTo.file("b.ts"); - } - - goTo.position(r.start); - verify.documentHighlightsAtPositionCount(3, ["a.ts", "b.ts"]); - - for (let range of ranges) { - verify.documentHighlightsAtPositionContains(range, ["a.ts", "b.ts"]); - } -} +verify.rangesAreDocumentHighlights();