diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 6a4e13b22e3..9dad3dddf60 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -146,7 +146,7 @@ module FourSlash { function convertGlobalOptionsToCompilationSettings(globalOptions: { [idx: string]: string }): ts.CompilationSettings { var settings: ts.CompilationSettings = {}; - // Convert all property in globalOptions into ts.CompilationSettings + // Convert all property in globalOptions into ts.CompilationSettings for (var prop in globalOptions) { if (globalOptions.hasOwnProperty(prop)) { switch (prop) { @@ -1610,7 +1610,7 @@ module FourSlash { Harness.IO.log(this.getNameOrDottedNameSpan(pos)); } - private verifyClassifications(expected: { classificationType: string; text: string }[], actual: ts.ClassifiedSpan[]) { + private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[]) { if (actual.length !== expected.length) { this.raiseError('verifyClassifications failed - expected total classifications to be ' + expected.length + ', but was ' + actual.length); } @@ -1626,7 +1626,19 @@ module FourSlash { actualClassification.classificationType); } + var expectedSpan = expectedClassification.textSpan; var actualSpan = actualClassification.textSpan; + + if (expectedSpan) { + var expectedLength = expectedSpan.end - expectedSpan.start; + + if (expectedSpan.start !== actualSpan.start() || expectedLength !== actualSpan.length()) { + this.raiseError("verifyClassifications failed - expected span of text to be " + + "{start=" + expectedSpan.start + ", length=" + expectedLength + "}, but was " + + "{start=" + actualSpan.start() + ", length=" + actualSpan.length() + "}"); + } + } + var actualText = this.activeFile.content.substr(actualSpan.start(), actualSpan.length()); if (expectedClassification.text !== actualText) { this.raiseError('verifyClassifications failed - expected classificatied text to be ' + diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 7be7dd63c92..d184be57712 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -80,6 +80,10 @@ module FourSlashInterface { return FourSlash.currentTestState.getMarkers(); } + public marker(name?: string): Marker { + return FourSlash.currentTestState.getMarkerByName(name); + } + public ranges(): Range[] { return FourSlash.currentTestState.getRanges(); } @@ -401,11 +405,17 @@ module FourSlashInterface { FourSlash.currentTestState.verifyCompletionEntryDetails(entryName, text, documentation, kind); } + /** + * This method *requires* a contiguous, complete, and ordered stream of classifications for a file. + */ public syntacticClassificationsAre(...classifications: { classificationType: string; text: string }[]) { FourSlash.currentTestState.verifySyntacticClassifications(classifications); } - public semanticClassificationsAre(...classifications: { classificationType: string; text: string }[]) { + /** + * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended. + */ + public semanticClassificationsAre(...classifications: { classificationType: string; text: string; textSpan?: TextSpan }[]) { FourSlash.currentTestState.verifySemanticClassifications(classifications); } @@ -563,61 +573,69 @@ module FourSlashInterface { } } - export class classification { - public static comment(text: string): { classificationType: string; text: string } { - return { classificationType: "comment", text: text }; + export module classification { + export function comment(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("comment", text, position); } - public static identifier(text: string): { classificationType: string; text: string } { - return { classificationType: "identifier", text: text }; + export function identifier(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("identifier", text, position); } - public static keyword(text: string): { classificationType: string; text: string } { - return { classificationType: "keyword", text: text }; + export function keyword(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("keyword", text, position); } - public static numericLiteral(text: string): { classificationType: string; text: string } { - return { classificationType: "numericLiteral", text: text }; + export function numericLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("numericLiteral", text, position); } - public static operator(text: string): { classificationType: string; text: string } { - return { classificationType: "operator", text: text }; + export function operator(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("operator", text, position); } - public static stringLiteral(text: string): { classificationType: string; text: string } { - return { classificationType: "stringLiteral", text: text }; + export function stringLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("stringLiteral", text, position); } - public static whiteSpace(text: string): { classificationType: string; text: string } { - return { classificationType: "whiteSpace", text: text }; + export function whiteSpace(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("whiteSpace", text, position); } - public static text(text: string): { classificationType: string; text: string } { - return { classificationType: "text", text: text }; + export function text(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("text", text, position); } - public static punctuation(text: string): { classificationType: string; text: string } { - return { classificationType: "punctuation", text: text }; + export function punctuation(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("punctuation", text, position); } - public static className(text: string): { classificationType: string; text: string } { - return { classificationType: "className", text: text }; + export function className(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("className", text, position); } - public static enumName(text: string): { classificationType: string; text: string } { - return { classificationType: "enumName", text: text }; + export function enumName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("enumName", text, position); } - public static interfaceName(text: string): { classificationType: string; text: string } { - return { classificationType: "interfaceName", text: text }; + export function interfaceName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("interfaceName", text, position); } - public static moduleName(text: string): { classificationType: string; text: string } { - return { classificationType: "moduleName", text: text }; + export function moduleName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("moduleName", text, position); } - public static typeParameterName(text: string): { classificationType: string; text: string } { - return { classificationType: "typeParameterName", text: text }; + export function typeParameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { + return getClassification("typeParameterName", text, position); + } + + function getClassification(type: string, text: string, position?: number) { + return { + classificationType: type, + text: text, + textSpan: position === undefined ? undefined : { start: position, end: position + text.length } + }; } } } @@ -635,6 +653,7 @@ module fs { function verifyOperationIsCancelled(f) { FourSlash.verifyOperationIsCancelled(f); } + var test = new FourSlashInterface.test_(); var goTo = new FourSlashInterface.goTo(); var verify = new FourSlashInterface.verify(); diff --git a/tests/cases/fourslash/semanticClassification1.ts b/tests/cases/fourslash/semanticClassification1.ts index ad9e88ea842..4eb7f2a32ed 100644 --- a/tests/cases/fourslash/semanticClassification1.ts +++ b/tests/cases/fourslash/semanticClassification1.ts @@ -1,11 +1,15 @@ /// -//// module M { -//// export interface I { +//// module /*0*/M { +//// export interface /*1*/I { //// } //// } -//// interface X extends M.I { } +//// interface /*2*/X extends /*3*/M./*4*/I { } var c = classification; verify.semanticClassificationsAre( - c.moduleName("M"), c.interfaceName("I"), c.interfaceName("X"), c.moduleName("M"), c.interfaceName("I")); + c.moduleName("M", test.marker("0").position), + c.interfaceName("I", test.marker("1").position), + c.interfaceName("X", test.marker("2").position), + c.moduleName("M", test.marker("3").position), + c.interfaceName("I", test.marker("4").position)); diff --git a/tests/cases/fourslash/semanticClassification2.ts b/tests/cases/fourslash/semanticClassification2.ts index 810636dba3e..f7f6340e5bd 100644 --- a/tests/cases/fourslash/semanticClassification2.ts +++ b/tests/cases/fourslash/semanticClassification2.ts @@ -1,6 +1,6 @@ /// -//// interface Thing { +//// interface /*0*/Thing { //// toExponential(): number; //// } //// @@ -8,4 +8,4 @@ //// Thing.toExponential(); var c = classification; -verify.semanticClassificationsAre(c.interfaceName("Thing")); \ No newline at end of file +verify.semanticClassificationsAre(c.interfaceName("Thing", test.marker("0").position)); \ No newline at end of file diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts index 96cce6f4255..2b8b6824558 100644 --- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts +++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts @@ -1,20 +1,24 @@ /// -////module M { -//// export interface I { +////module /*0*/M { +//// export interface /*1*/I { //// } //// var x = 10; ////} //// -////var M = { +////var /*2*/M = { //// foo: 10, //// bar: 20 ////} //// -////var v: M.I; +////var v: /*3*/M./*4*/I; //// -////var x = M; +////var x = /*5*/M; var c = classification; verify.semanticClassificationsAre( - c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.interfaceName("I"), c.moduleName("M")); + c.moduleName("M", test.marker("0").position), + c.interfaceName("I", test.marker("1").position), + c.moduleName("M", test.marker("3").position), + c.interfaceName("I", test.marker("4").position), + c.moduleName("M", test.marker("5").position)); diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts index bcbd5f514f4..5d2ed9844cc 100644 --- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts @@ -1,23 +1,28 @@ /// -////module M { -//// export interface I { +////module /*0*/M { +//// export interface /*1*/I { //// } ////} //// -////module M { +////module /*2*/M { //// var x = 10; ////} //// -////var M = { +////var /*3*/M = { //// foo: 10, //// bar: 20 ////} //// -////var v: M.I; +////var v: /*4*/M./*5*/I; //// -////var x = M; +////var x = /*6*/M; var c = classification; verify.semanticClassificationsAre( - c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.moduleName("M"), c.interfaceName("I"), c.moduleName("M")); + c.moduleName("M", test.marker("0").position), + c.interfaceName("I", test.marker("1").position), + c.moduleName("M", test.marker("2").position), + c.moduleName("M", test.marker("4").position), + c.interfaceName("I", test.marker("5").position), + c.moduleName("M", test.marker("6").position)); diff --git a/tests/cases/fourslash/semanticClassificationModules.ts b/tests/cases/fourslash/semanticClassificationModules.ts index fc75b3bba98..86c2819983a 100644 --- a/tests/cases/fourslash/semanticClassificationModules.ts +++ b/tests/cases/fourslash/semanticClassificationModules.ts @@ -1,13 +1,19 @@ /// -////module M { +////module /*0*/M { //// export var v; -//// export interface I { +//// export interface /*1*/I { //// } ////} //// -////var x: M.I = M.v; -////var y = M; +////var x: /*2*/M./*3*/I = /*4*/M.v; +////var y = /*5*/M; var c = classification; -verify.semanticClassificationsAre(c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.moduleName("M")); \ No newline at end of file +verify.semanticClassificationsAre( + c.moduleName("M", test.marker("0").position), + c.interfaceName("I", test.marker("1").position), + c.moduleName("M", test.marker("2").position), + c.interfaceName("I", test.marker("3").position), + c.moduleName("M", test.marker("4").position), + c.moduleName("M", test.marker("5").position)); \ No newline at end of file diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts index fb3717006fe..e7486c2c0cb 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts @@ -1,7 +1,7 @@ /// -////declare module M { -//// interface I { +////declare module /*0*/M { +//// interface /*1*/I { //// //// } ////} @@ -9,4 +9,6 @@ ////var M = { I: 10 }; var c = classification; -verify.semanticClassificationsAre(c.moduleName("M"), c.interfaceName("I")); \ No newline at end of file +verify.semanticClassificationsAre( + c.moduleName("M", test.marker("0").position), + c.interfaceName("I", test.marker("1").position)); \ No newline at end of file diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts index 295af091e75..f90efd7518d 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts @@ -1,19 +1,22 @@ /// -////module M { -//// export interface I { +////module /*0*/M { +//// export interface /*1*/I { //// } ////} //// -////var M = { +////var /*2*/M = { //// foo: 10, //// bar: 20 ////} //// -////var v: M.I; +////var v: /*3*/M./*4*/I; //// -////var x = M; +////var x = /*5*/M; var c = classification; verify.semanticClassificationsAre( - c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.interfaceName("I")); + c.moduleName("M", test.marker("0").position), + c.interfaceName("I", test.marker("1").position), + c.moduleName("M", test.marker("3").position), + c.interfaceName("I", test.marker("4").position)); diff --git a/tests/cases/fourslash/syntacticClassifications1.ts b/tests/cases/fourslash/syntacticClassifications1.ts index e70a4b672ff..88f655683a3 100644 --- a/tests/cases/fourslash/syntacticClassifications1.ts +++ b/tests/cases/fourslash/syntacticClassifications1.ts @@ -18,7 +18,6 @@ //// } //// } -debugger; var c = classification; verify.syntacticClassificationsAre( c.comment("// comment"),