From 094d76baecccf4618e7aa1d93ac8b46b0029c15c Mon Sep 17 00:00:00 2001 From: Philip Heltweg Date: Fri, 1 Sep 2023 15:50:11 +0200 Subject: [PATCH] Added validation tests for composite blocktypes --- .../composite-blocktype-definition.spec.ts | 122 ++++++++++++++++++ ...-composite-blocktype-multiple-pipelines.jv | 27 ++++ ...invalid-composite-blocktype-no-pipeline.jv | 10 ++ .../valid-composite-blocktype-extractor.jv | 28 ++++ .../valid-composite-blocktype-recursive.jv | 42 ++++++ 5 files changed, 229 insertions(+) create mode 100644 libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts create mode 100644 libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-multiple-pipelines.jv create mode 100644 libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-no-pipeline.jv create mode 100644 libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-extractor.jv create mode 100644 libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-recursive.jv diff --git a/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts b/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts new file mode 100644 index 000000000..e30fd3bf5 --- /dev/null +++ b/libs/language-server/src/lib/validation/checks/composite-blocktype-definition.spec.ts @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +import { AstNode, AstNodeLocator, LangiumDocument } from 'langium'; +import { NodeFileSystem } from 'langium/node'; + +import { + CompositeBlocktypeDefinition, + EvaluationContext, + RuntimeParameterProvider, + ValidationContext, + createJayveeServices, + useExtension, +} from '../..'; +import { + ParseHelperOptions, + expectNoParserAndLexerErrors, + parseHelper, + readJvTestAssetHelper, + validationAcceptorMockImpl, +} from '../../../test'; +import { TestLangExtension } from '../../../test/extension'; + +import { validateCompositeBlockTypeDefinition } from './composite-blocktype-definition'; + +describe('Validation of CompositeBlocktypeDefinition', () => { + let parse: ( + input: string, + options?: ParseHelperOptions, + ) => Promise>; + + const validationAcceptorMock = jest.fn(validationAcceptorMockImpl); + + let locator: AstNodeLocator; + + const readJvTestAsset = readJvTestAssetHelper( + __dirname, + '../../../test/assets/', + ); + + async function parseAndValidateBlocktype(input: string) { + const document = await parse(input); + expectNoParserAndLexerErrors(document); + + const blocktype = locator.getAstNode( + document.parseResult.value, + 'blocktypes@0', + ) as CompositeBlocktypeDefinition; + + validateCompositeBlockTypeDefinition( + blocktype, + new ValidationContext(validationAcceptorMock), + new EvaluationContext(new RuntimeParameterProvider()), + ); + } + + beforeAll(() => { + // Register test extension + useExtension(new TestLangExtension()); + // Create language services + const services = createJayveeServices(NodeFileSystem).Jayvee; + locator = services.workspace.AstNodeLocator; + // Parse function for Jayvee (without validation) + parse = parseHelper(services); + }); + + afterEach(() => { + // Reset mock + validationAcceptorMock.mockReset(); + }); + + it('should diagnose error on missing pipeline in composite blocktype', async () => { + const text = readJvTestAsset( + 'composite-blocktype-definition/invalid-composite-blocktype-no-pipeline.jv', + ); + + await parseAndValidateBlocktype(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(1); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + `Composite blocktypes must define one pipeline 'TestBlock'`, + expect.any(Object), + ); + }); + + it('should diagnose error on multiple pipelines in composite blocktype', async () => { + const text = readJvTestAsset( + 'composite-blocktype-definition/invalid-composite-blocktype-multiple-pipelines.jv', + ); + + await parseAndValidateBlocktype(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(2); + expect(validationAcceptorMock).toHaveBeenCalledWith( + 'error', + `Found more than one pipeline definition in composite blocktype 'TestBlock'`, + expect.any(Object), + ); + }); + + it('should have no error on valid extractor blocktype definition', async () => { + const text = readJvTestAsset( + 'composite-blocktype-definition/valid-composite-blocktype-extractor.jv', + ); + + await parseAndValidateBlocktype(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); + + it('should have no error on valid extractor blocktype definition using recursion', async () => { + const text = readJvTestAsset( + 'composite-blocktype-definition/valid-composite-blocktype-recursive.jv', + ); + + await parseAndValidateBlocktype(text); + + expect(validationAcceptorMock).toHaveBeenCalledTimes(0); + }); +}); diff --git a/libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-multiple-pipelines.jv b/libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-multiple-pipelines.jv new file mode 100644 index 000000000..60e4550ae --- /dev/null +++ b/libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-multiple-pipelines.jv @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +composite blocktype TestBlock { + + input inputName oftype None; + output outputName oftype Sheet; + + block FileExtractor oftype HttpExtractor { url: 'url'; } + block FileTextInterpreter oftype TextFileInterpreter {} + + block FileCSVInterpreter oftype CSVInterpreter { + } + + inputName + ->FileExtractor + ->FileTextInterpreter + ->FileCSVInterpreter + ->outputName; + + inputName + ->FileExtractor + ->FileTextInterpreter + ->FileCSVInterpreter + ->outputName; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-no-pipeline.jv b/libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-no-pipeline.jv new file mode 100644 index 000000000..638e87ef6 --- /dev/null +++ b/libs/language-server/src/test/assets/composite-blocktype-definition/invalid-composite-blocktype-no-pipeline.jv @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +composite blocktype TestBlock { + property test oftype text; + + input inputName oftype None; + output outputName oftype Sheet; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-extractor.jv b/libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-extractor.jv new file mode 100644 index 000000000..01c3e975f --- /dev/null +++ b/libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-extractor.jv @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +composite blocktype CSVExtractor { + property url oftype text; + property delimiter oftype text: ','; + property enclosing oftype text: ''; + property enclosingEscape oftype text: ''; + + input inputName oftype None; + output outputName oftype Sheet; + + block FileExtractor oftype HttpExtractor { url: url; } + block FileTextInterpreter oftype TextFileInterpreter {} + + block FileCSVInterpreter oftype CSVInterpreter { + delimiter: delimiter; + enclosing: enclosing; + enclosingEscape: enclosingEscape; + } + + inputName + ->FileExtractor + ->FileTextInterpreter + ->FileCSVInterpreter + ->outputName; +} \ No newline at end of file diff --git a/libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-recursive.jv b/libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-recursive.jv new file mode 100644 index 000000000..dfb2b5a06 --- /dev/null +++ b/libs/language-server/src/test/assets/composite-blocktype-definition/valid-composite-blocktype-recursive.jv @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +composite blocktype TextFileExtractor { + property url oftype text; + + input inputName oftype None; + output outputName oftype File; + + block FileExtractor oftype HttpExtractor { url: url; } + + block FileTextInterpreter oftype TextFileInterpreter {} + + inputName + ->FileExtractor + ->FileTextInterpreter + ->outputName; +} + +composite blocktype CSVExtractor { + property url oftype text; + property delimiter oftype text: ','; + property enclosing oftype text: ''; + property enclosingEscape oftype text: ''; + + input inputName oftype None; + output outputName oftype Sheet; + + block TextFileExtractor oftype TextFileExtractor { url: url; } + + block FileCSVInterpreter oftype CSVInterpreter { + delimiter: delimiter; + enclosing: enclosing; + enclosingEscape: enclosingEscape; + } + + inputName + ->TextFileExtractor + ->FileCSVInterpreter + ->outputName; +} \ No newline at end of file