From 0591e1bd206cdf0a7718656779a6f4091ae60d0f Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 9 Nov 2016 17:47:52 -0800 Subject: [PATCH] Simplify Testing --- src/harness/fourslash.ts | 111 ++++++------------ ...assExtendsAbstractSomePropertiesPresent.ts | 2 +- ...UnImplementedInterfaceDuplicateMember1.ts} | 7 +- ...xUnImplementedInterfaceDuplicateMember2.ts | 14 +++ ...MissingMultipleImplementsIntersection1.ts} | 6 +- ...eMissingMultipleImplementsIntersection2.ts | 14 +++ tests/cases/fourslash/fourslash.ts | 8 +- 7 files changed, 68 insertions(+), 94 deletions(-) rename tests/cases/fourslash/{codeFixUnImplementedInterfaceDuplicateMember.ts => codeFixUnImplementedInterfaceDuplicateMember1.ts} (54%) create mode 100644 tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember2.ts rename tests/cases/fourslash/{codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection.ts => codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection1.ts} (65%) create mode 100644 tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection2.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index b832e12711b..542b0b765ab 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -92,18 +92,6 @@ namespace FourSlash { end: number; } - export interface CodeFixIdentifier { - /** - * Error code to search over for codefix. - */ - code: number; - /** - * In a file where there is more than one error with code `code`, `count` refers - * to which 0-indexed codefix, sorted by order of occurence, to consider. - */ - count: number; - } - export import IndentStyle = ts.IndentStyle; const entityMap = ts.createMap({ @@ -1609,12 +1597,6 @@ namespace FourSlash { return runningOffset; } - private applyCodeAction(action: ts.CodeAction): void { - for (const filechange of action.changes) { - this.applyEdits(filechange.fileName, filechange.textChanges, /*isFormattingEdit*/ false); - } - } - public copyFormatOptions(): ts.FormatCodeSettings { return ts.clone(this.formatCodeSettings); } @@ -2034,31 +2016,22 @@ namespace FourSlash { /** * Compares expected text to the text that would be in the sole range - * (ie: [|...|]) in the file after applying the codefix corresponding - * to the error with errorCode, or of the sole error in the source file. + * (ie: [|...|]) in the file after applying the codefix sole codefix + * in the source file. * * Because codefixes are only applied on the working file, it is unsafe * to apply this more than once (consider a refactoring across files). */ - public verifyRangeAfterCodeFix(expectedText: string, codeFixIdentifier?: CodeFixIdentifier) { + public verifyRangeAfterCodeFix(expectedText: string) { const ranges = this.getRanges(); if (ranges.length !== 1) { this.raiseError("Exactly one range should be specified in the testfile."); } const fileName = this.activeFile.fileName; - const codeFix: ts.CodeAction = this.getCodeFix(fileName, codeFixIdentifier); - if (!codeFix) { - this.raiseError("Should find exactly one codefix, but none found."); - } + this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName)); - const fileChange = ts.find(codeFix.changes, change => change.fileName === fileName); - if (!fileChange) { - this.raiseError("CodeFix found doesn't provide any changes in this file."); - } - - this.applyEdits(fileChange.fileName, fileChange.textChanges, /*isFormattingEdit*/ false); const actualText = this.rangeText(ranges[0]); if (this.removeWhitespace(actualText) !== this.removeWhitespace(expectedText)) { @@ -2069,33 +2042,16 @@ namespace FourSlash { /** * Applies fixes for the errors in fileName and compares the results to * expectedContents after all fixes have been applied. - * - * It is safe to apply this multiple times in a single test. - * + * Note: applying one codefix may generate another (eg: remove duplicate implements * may generate an extends -> interface conversion fix). * @param expectedContents The contents of the file after the fixes are applied. * @param fileName The file to check. If not supplied, the current open file is used. - * @param errorsToFix An array of errors for which quickfixes will be applied. If not - * supplied, all codefixes in the file are applied until none are left, starting from - * the first available codefix. - * */ - public verifyFileAfterCodeFix(expectedContents: string, fileName?: string, codeFixIdentifier?: CodeFixIdentifier) { + public verifyFileAfterCodeFix(expectedContents: string, fileName?: string) { fileName = fileName ? fileName : this.activeFile.fileName; - const codeFix = this.getCodeFix(fileName, codeFixIdentifier); - - if (codeFix === undefined) { - if (codeFixIdentifier) { - this.raiseError(`Couldn't find the ${codeFixIdentifier.count}'th error with code ${codeFixIdentifier.code}.`); - } - else { - this.raiseError("No code fix could be found."); - } - } - - this.applyCodeAction(codeFix); + this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName)); const actualContents: string = this.getFileContent(fileName); if (this.removeWhitespace(actualContents) !== this.removeWhitespace(expectedContents)) { @@ -2106,30 +2062,31 @@ namespace FourSlash { /** * Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found. * @param fileName Path to file where error should be retrieved from. - * @param error We get the `error.count`'th codefix with code `error.code`. - * - * If undefined, we get the first codefix available. */ - private getCodeFix(fileName: string, error?: CodeFixIdentifier): ts.CodeAction | undefined { + private getCodeFixActions(fileName: string): ts.CodeAction[] { const diagnostics: ts.Diagnostic[] = this.getDiagnostics(fileName); - const errorCount = error ? error.count : 0; - let countSeen = 0; + let actions: ts.CodeAction[] = undefined; for (const diagnostic of diagnostics) { - if (error && error.code !== diagnostic.code) { - continue; - } - const action = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code]); - if (action) { - if (action.length > errorCount - countSeen) { - return action[errorCount - countSeen]; - } - else { - countSeen += action.length; - } + const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code]); + if (newActions && newActions.length) { + actions = actions ? actions.concat(newActions) : newActions; } } - return undefined; + return actions; + } + + private applyCodeFixActions(fileName: string, actions: ts.CodeAction[]): void { + if (!(actions && actions.length === 1)) { + this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`); + } + + const fileChanges = ts.find(actions[0].changes, change => change.fileName === fileName); + if (!fileChanges) { + this.raiseError("The CodeFix found doesn't provide any changes in this file."); + } + + this.applyEdits(fileChanges.fileName, fileChanges.textChanges, /*isFormattingEdit*/ false); } public verifyDocCommentTemplate(expected?: ts.TextInsertion) { @@ -2404,8 +2361,8 @@ namespace FourSlash { } } - public verifyCodeFixAvailable(negative: boolean, errorCode?: number) { - const codeFix = this.getCodeFix(this.activeFile.fileName, errorCode ? { code: errorCode, count: 0 } : undefined); + public verifyCodeFixAvailable(negative: boolean) { + const codeFix = this.getCodeFixActions(this.activeFile.fileName); if (negative && codeFix) { this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found one.`); @@ -3199,8 +3156,8 @@ namespace FourSlashInterface { this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace); } - public codeFixAvailable(errorCode?: number) { - this.state.verifyCodeFixAvailable(this.negative, errorCode); + public codeFixAvailable() { + this.state.verifyCodeFixAvailable(this.negative); } } @@ -3385,12 +3342,12 @@ namespace FourSlashInterface { this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true); } - public rangeAfterCodeFix(expectedText: string, codeFixidentifier?: FourSlash.CodeFixIdentifier): void { - this.state.verifyRangeAfterCodeFix(expectedText, codeFixidentifier); + public rangeAfterCodeFix(expectedText: string): void { + this.state.verifyRangeAfterCodeFix(expectedText); } - public fileAfterCodeFix(expectedContents: string, fileName?: string, codeFixidentifier?: FourSlash.CodeFixIdentifier): void { - this.state.verifyFileAfterCodeFix(expectedContents, fileName, codeFixidentifier); + public fileAfterCodeFix(expectedContents: string, fileName?: string): void { + this.state.verifyFileAfterCodeFix(expectedContents, fileName); } public navigationBar(json: any) { diff --git a/tests/cases/fourslash/codeFixClassExtendsAbstractSomePropertiesPresent.ts b/tests/cases/fourslash/codeFixClassExtendsAbstractSomePropertiesPresent.ts index 60adfb5d319..b6dd679bb71 100644 --- a/tests/cases/fourslash/codeFixClassExtendsAbstractSomePropertiesPresent.ts +++ b/tests/cases/fourslash/codeFixClassExtendsAbstractSomePropertiesPresent.ts @@ -7,7 +7,7 @@ //// } //// //// class C extends A {[| |] -//// constructor(public x: number) { } +//// constructor(public x: number) { super(); } //// y: number; //// } diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember1.ts similarity index 54% rename from tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember.ts rename to tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember1.ts index 5d0651b009d..a2154de567a 100644 --- a/tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember.ts +++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember1.ts @@ -7,10 +7,7 @@ //// x: number; //// } //// -//// class C1 implements I1,I2 {[| +//// class C implements I1,I2 {[| //// |]} -verify.rangeAfterCodeFix(` -x: number; -`); -verify.not.codeFixAvailable(); \ No newline at end of file +verify.codeFixAvailable(); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember2.ts b/tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember2.ts new file mode 100644 index 00000000000..ac90d51b07c --- /dev/null +++ b/tests/cases/fourslash/codeFixUnImplementedInterfaceDuplicateMember2.ts @@ -0,0 +1,14 @@ +/// + +//// interface I1 { +//// x: number; +//// } +//// interface I2 { +//// x: number; +//// } +//// +//// class C implements I1,I2 { +//// x: number; +//// } + +verify.not.codeFixAvailable(); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection.ts b/tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection1.ts similarity index 65% rename from tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection.ts rename to tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection1.ts index 1aa7ef7cdb5..321d41e4633 100644 --- a/tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection.ts +++ b/tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection1.ts @@ -10,8 +10,4 @@ //// class C implements I1,I2 {[| //// |]} -verify.rangeAfterCodeFix(` - x: number; -`); - -verify.not.codeFixAvailable(); \ No newline at end of file +verify.codeFixAvailable(); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection2.ts b/tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection2.ts new file mode 100644 index 00000000000..8f744e25cae --- /dev/null +++ b/tests/cases/fourslash/codeFixUnimplementedInterfaceMissingMultipleImplementsIntersection2.ts @@ -0,0 +1,14 @@ +/// + +//// interface I1 { +//// x: number; +//// } +//// interface I2 { +//// x: string; +//// } +//// +//// class C implements I1,I2 { +//// x: string; +//// } + +verify.not.codeFixAvailable(); \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index b663d2825b7..10f990fdb84 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -98,10 +98,6 @@ declare namespace FourSlashInterface { start: number; end: number; } - interface CodeFixIdentifier { - code: number; - count: number - } class test_ { markers(): Marker[]; markerNames(): string[]; @@ -214,8 +210,8 @@ declare namespace FourSlashInterface { noMatchingBracePositionInCurrentFile(bracePosition: number): void; DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void; noDocCommentTemplate(): void; - rangeAfterCodeFix(expectedText: string, CodeFixIdentifier?: CodeFixIdentifier): void; - fileAfterCodeFix(expectedContents: string, fileName?: string, CodeFixIdentifier?: CodeFixIdentifier): void; + rangeAfterCodeFix(expectedText: string): void; + fileAfterCodeFix(expectedContents: string, fileName?: string): void; navigationBar(json: any): void; navigationTree(json: any): void;