Merge pull request #13546 from Microsoft/test_document_highlights
Update document highlight tests: Use ranges to represent expected highlights
This commit is contained in:
commit
ae8fd30444
14 changed files with 135 additions and 193 deletions
|
@ -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<T>(inputs: T[], getOutput: (t: T) => string): string[] {
|
||||
const set = ts.createMap<true>();
|
||||
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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"]);
|
||||
}
|
||||
verify.rangesWithSameTextAreDocumentHighlights();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"]);
|
||||
verify.rangesWithSameTextAreDocumentHighlights();
|
||||
|
|
|
@ -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"]);
|
||||
const [Cprop0, Cprop1, Dprop0, Dprop1, prop1Use] = test.ranges();
|
||||
verify.rangesAreDocumentHighlights([Cprop0]);
|
||||
verify.rangesAreDocumentHighlights([Dprop0]);
|
||||
verify.rangesAreDocumentHighlights([Cprop1]);
|
||||
verify.rangesAreDocumentHighlights([Dprop1, prop1Use]);
|
||||
|
|
|
@ -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"]);
|
||||
}
|
||||
verify.rangesWithSameTextAreDocumentHighlights();
|
||||
|
|
|
@ -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"]);
|
||||
}
|
||||
verify.rangesWithSameTextAreDocumentHighlights();
|
||||
|
|
|
@ -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"]);
|
||||
}
|
||||
verify.rangesWithSameTextAreDocumentHighlights();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"]);
|
||||
verify.rangesAreDocumentHighlights();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -8,28 +8,10 @@
|
|||
|
||||
// @Filename: b.ts
|
||||
/////// <reference path="a.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();
|
||||
|
|
Loading…
Reference in a new issue