-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: data-driven tests for code actions
- Loading branch information
1 parent
c2c75f7
commit 25d7cfc
Showing
9 changed files
with
464 additions
and
30 deletions.
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
packages/safe-ds-lang/src/language/codeActions/factories.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { CodeAction, Diagnostic, TextEdit } from 'vscode-languageserver'; | ||
import { LangiumDocument } from 'langium'; | ||
|
||
export const createQuickfixFromTextEditsToSingleDocument = ( | ||
title: string, | ||
diagnostic: Diagnostic, | ||
document: LangiumDocument, | ||
edits: TextEdit[], | ||
isPreferred: boolean = false, | ||
): CodeAction => { | ||
return { | ||
title, | ||
kind: 'quickfix', | ||
diagnostics: [diagnostic], | ||
edit: { | ||
documentChanges: [ | ||
{ | ||
textDocument: { | ||
uri: document.textDocument.uri, | ||
version: document.textDocument.version, | ||
}, | ||
edits, | ||
}, | ||
], | ||
}, | ||
isPreferred, | ||
}; | ||
}; |
35 changes: 13 additions & 22 deletions
35
packages/safe-ds-lang/src/language/codeActions/quickfixes/arguments.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
packages/safe-ds-lang/tests/language/codeActions/creator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import { | ||
listTestFilesWithExtensions, | ||
listTestSafeDsFilesGroupedByParentDirectory, | ||
loadDocuments, | ||
uriToShortenedTestResourceName, | ||
} from '../../helpers/testResources.js'; | ||
import path from 'path'; | ||
import { getSyntaxErrors, SyntaxErrorsInCodeError } from '../../helpers/diagnostics.js'; | ||
import { NodeFileSystem } from 'langium/node'; | ||
import { TestDescription, TestDescriptionError } from '../../helpers/testDescription.js'; | ||
import { URI } from 'langium'; | ||
import { createSafeDsServices } from '../../../src/language/index.js'; | ||
import { findTestComments } from '../../helpers/testComments.js'; | ||
import { SAFE_DS_FILE_EXTENSIONS } from '../../../src/language/helpers/fileExtensions.js'; | ||
|
||
const services = (await createSafeDsServices(NodeFileSystem)).SafeDs; | ||
const langiumDocuments = services.shared.workspace.LangiumDocuments; | ||
|
||
const rootResourceName = 'code actions'; | ||
const commentRegex = /\s*apply\s*(?<titleIsRegex>r)?"(?<title>.*)"/gu; | ||
|
||
export const createCodeActionsTests = async (): Promise<CodeActionsTest[]> => { | ||
const filesGroupedByParentDirectory = listTestSafeDsFilesGroupedByParentDirectory(rootResourceName); | ||
const testCases = filesGroupedByParentDirectory.map((entry) => createCodeActionsTest(...entry)); | ||
|
||
return Promise.all(testCases); | ||
}; | ||
|
||
const createCodeActionsTest = async (parentDirectory: URI, inputUris: URI[]): Promise<CodeActionsTest> => { | ||
const outputRoot = URI.file(path.join(parentDirectory.fsPath, 'skip-output')); | ||
const expectedOutputUris = listExpectedOutputFiles(outputRoot); | ||
const inputs: CodeActionsInput[] = []; | ||
|
||
// Load all files, so they get linked | ||
await loadDocuments(services, inputUris, { validation: true }); | ||
|
||
for (const uri of inputUris) { | ||
const document = langiumDocuments.getDocument(uri)!; | ||
const code = document.textDocument.getText(); | ||
|
||
// File must not contain syntax errors | ||
const syntaxErrors = await getSyntaxErrors(services, code); | ||
if (syntaxErrors.length > 0) { | ||
return invalidTest('FILE', new SyntaxErrorsInCodeError(syntaxErrors, uri)); | ||
} | ||
|
||
const testComments = findTestComments(code); | ||
const codeActionTitles: (string | RegExp)[] = []; | ||
|
||
for (const comment of testComments) { | ||
const match = commentRegex.exec(comment); | ||
|
||
// Comment must match the expected format | ||
if (!match) { | ||
return invalidTest('FILE', new InvalidCommentError(comment, uri)); | ||
} | ||
|
||
const title = match.groups!.title!; | ||
const titleIsRegex = match.groups!.titleIsRegex === 'r'; | ||
|
||
codeActionTitles.push(titleIsRegex ? new RegExp(title, 'gu') : title); | ||
} | ||
|
||
inputs.push({ uri, codeActionTitles }); | ||
} | ||
|
||
const shortenedResourceName = uriToShortenedTestResourceName(parentDirectory, rootResourceName); | ||
return { | ||
testName: `[${shortenedResourceName}]`, | ||
inputs, | ||
inputRoot: parentDirectory, | ||
expectedOutputUris, | ||
outputRoot, | ||
}; | ||
}; | ||
|
||
/** | ||
* List all expected output files. | ||
* | ||
* @param outputRoot The directory, where output files are located. | ||
*/ | ||
const listExpectedOutputFiles = (outputRoot: URI): URI[] => { | ||
return listTestFilesWithExtensions(uriToShortenedTestResourceName(outputRoot), SAFE_DS_FILE_EXTENSIONS); | ||
}; | ||
|
||
/** | ||
* Report a test that has errors. | ||
* | ||
* @param level Whether a test file or a test suite is invalid. | ||
* @param error The error that occurred. | ||
*/ | ||
const invalidTest = (level: 'FILE' | 'SUITE', error: TestDescriptionError): CodeActionsTest => { | ||
const shortenedResourceName = uriToShortenedTestResourceName(error.uri, rootResourceName); | ||
const testName = `INVALID TEST ${level} [${shortenedResourceName}]`; | ||
return { | ||
testName, | ||
inputs: [], | ||
inputRoot: URI.file(''), | ||
expectedOutputUris: [], | ||
outputRoot: URI.file(''), | ||
error, | ||
}; | ||
}; | ||
|
||
/** | ||
* A description of a code actions test. | ||
*/ | ||
interface CodeActionsTest extends TestDescription { | ||
/** | ||
* The original code. | ||
*/ | ||
inputs: CodeActionsInput[]; | ||
|
||
/** | ||
* The directory, where input files are located. | ||
*/ | ||
inputRoot: URI; | ||
|
||
/** | ||
* The expected output files. | ||
*/ | ||
expectedOutputUris: URI[]; | ||
|
||
/** | ||
* The directory, where output files are located. | ||
*/ | ||
outputRoot: URI; | ||
} | ||
|
||
/** | ||
* A description of the input for code actions. | ||
*/ | ||
interface CodeActionsInput { | ||
/** | ||
* The URI of the file. | ||
*/ | ||
uri: URI; | ||
|
||
/** | ||
* The titles of the code actions that should be applied. Strings must match exactly, regular expressions must match | ||
* the entire string. | ||
*/ | ||
codeActionTitles: (string | RegExp)[]; | ||
} | ||
|
||
/** | ||
* A test comment did not match the expected format. | ||
*/ | ||
class InvalidCommentError extends TestDescriptionError { | ||
constructor( | ||
readonly comment: string, | ||
uri: URI, | ||
) { | ||
super(`Invalid test comment (refer to the documentation for guidance): ${comment}`, uri); | ||
} | ||
} |
Oops, something went wrong.