diff --git a/libs/interpreter-lib/src/parsing-util.spec.ts b/libs/interpreter-lib/src/parsing-util.spec.ts new file mode 100644 index 000000000..f2125c9e0 --- /dev/null +++ b/libs/interpreter-lib/src/parsing-util.spec.ts @@ -0,0 +1,189 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +import * as path from 'path'; + +import { TestLogger } from '@jvalue/jayvee-execution/test'; +import { + JayveeServices, + createJayveeServices, + useExtension, +} from '@jvalue/jayvee-language-server'; +import { + ParseHelperOptions, + TestLangExtension, + expectNoParserAndLexerErrors, + parseHelper, + readJvTestAssetHelper, +} from '@jvalue/jayvee-language-server/test'; +import { AstNode, LangiumDocument } from 'langium'; +import { NodeFileSystem } from 'langium/node'; + +import { extractDocumentFromFile, validateDocument } from './parsing-util'; + +describe('Validation of parsing-util', () => { + let parse: ( + input: string, + options?: ParseHelperOptions, + ) => Promise>; + + let exitSpy: jest.SpyInstance; + + let services: JayveeServices; + + const logger = new TestLogger(true, undefined, false); + + const readJvTestAsset = readJvTestAssetHelper( + __dirname, + '../test/assets/parsing-util/', + ); + + beforeAll(() => { + // Mock Process.exit + exitSpy = jest + .spyOn(process, 'exit') + .mockImplementation((code?: number) => { + if (code === undefined || code === 0) { + return undefined as never; + } + throw new Error(`process.exit: ${code}`); + }); + + // Register test extension + useExtension(new TestLangExtension()); + // Create language services + services = createJayveeServices(NodeFileSystem).Jayvee; + // Parse function for Jayvee (without validation) + parse = parseHelper(services); + }); + + afterEach(() => { + exitSpy.mockClear(); + logger.clearLogs(); + }); + + describe('Function of validateDocument', () => { + async function parseAndValidateDocument(input: string) { + const document = await parse(input); + expectNoParserAndLexerErrors(document); + + return validateDocument(document, services, logger); + } + + it('should diagnose no error on valid document', async () => { + const text = readJvTestAsset('validateDocument/valid-document.jv'); + + await parseAndValidateDocument(text); + + expect(exitSpy).toHaveBeenCalledTimes(0); + expect(logger.getLogs().infoLogs).toHaveLength(0); + expect(logger.getLogs().errorLogs).toHaveLength(0); + expect(logger.getLogs().debugLogs).toHaveLength(0); + expect(logger.getLogs().diagnosticLogs).toHaveLength(0); + }); + + it('should diagnose error on wrong loader type', async () => { + const text = readJvTestAsset( + 'validateDocument/invalid-wrong-loader-type.jv', + ); + + try { + await parseAndValidateDocument(text); + } catch (e) { + expect(exitSpy).toHaveBeenCalledTimes(1); + expect(exitSpy).toHaveBeenCalledWith(1); + expect(logger.getLogs().infoLogs).toHaveLength(0); + expect(logger.getLogs().errorLogs).toHaveLength(0); + expect(logger.getLogs().debugLogs).toHaveLength(0); + expect(logger.getLogs().diagnosticLogs).toHaveLength(2 * 5); // 2 calls that get formated to 5 lines each + } + }); + + it('should diagnose no error on nonErr diagnostics', async () => { + const text = readJvTestAsset( + 'validateDocument/valid-simplify-warning.jv', + ); + + try { + await parseAndValidateDocument(text); + } catch (e) { + expect(exitSpy).toHaveBeenCalledTimes(1); + expect(exitSpy).toHaveBeenCalledWith(1); + expect(logger.getLogs().infoLogs).toHaveLength(0); + expect(logger.getLogs().errorLogs).toHaveLength(0); + expect(logger.getLogs().debugLogs).toHaveLength(0); + expect(logger.getLogs().diagnosticLogs).toHaveLength(1); + } + }); + }); + + describe('Function of extractDocumentFromFile', () => { + it('should diagnose no error on valid model file', async () => { + await extractDocumentFromFile( + path.resolve( + __dirname, + '../test/assets/parsing-util/', + 'extractDocumentFromFile/valid-model.jv', + ), + services, + logger, + ); + + expect(exitSpy).toHaveBeenCalledTimes(0); + expect(logger.getLogs().infoLogs).toHaveLength(0); + expect(logger.getLogs().errorLogs).toHaveLength(0); + expect(logger.getLogs().debugLogs).toHaveLength(0); + expect(logger.getLogs().diagnosticLogs).toHaveLength(0); + }); + + it('should diagnose error on invalid extension', async () => { + try { + await extractDocumentFromFile( + path.resolve( + __dirname, + '../test/assets/parsing-util/', + 'extractDocumentFromFile/invalid-extension.lv', + ), + services, + logger, + ); + } catch (e) { + expect(exitSpy).toHaveBeenCalledTimes(1); + expect(logger.getLogs().infoLogs).toHaveLength(0); + expect(logger.getLogs().errorLogs).toHaveLength(1); + expect(logger.getLogs().errorLogs[0]).toEqual( + expect.stringContaining( + 'Please choose a file with this extension: ".jv"', + ), + ); + expect(logger.getLogs().debugLogs).toHaveLength(0); + expect(logger.getLogs().diagnosticLogs).toHaveLength(0); + } + }); + + it('should diagnose error on missing file', async () => { + try { + await extractDocumentFromFile( + path.resolve( + __dirname, + '../test/assets/parsing-util/', + 'extractDocumentFromFile/invalid-missing-file.jv', + ), + services, + logger, + ); + } catch (e) { + expect(exitSpy).toHaveBeenCalledTimes(1); + expect(logger.getLogs().infoLogs).toHaveLength(0); + expect(logger.getLogs().errorLogs).toHaveLength(1); + expect(logger.getLogs().errorLogs[0]).toMatch( + // eslint-disable-next-line no-useless-escape + /File [\w\-\/]*\/libs\/interpreter-lib\/test\/assets\/parsing-util\/extractDocumentFromFile\/invalid-missing-file\.jv does not exist\./, + ); + expect(logger.getLogs().debugLogs).toHaveLength(0); + expect(logger.getLogs().diagnosticLogs).toHaveLength(0); + } + }); + }); +}); diff --git a/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromFile/invalid-extension.lv b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromFile/invalid-extension.lv new file mode 100644 index 000000000..70f3794d1 --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromFile/invalid-extension.lv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline TestPipeline { + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestFileLoader { + } + + TestExtractor -> TestLoader; +} diff --git a/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromFile/valid-model.jv b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromFile/valid-model.jv new file mode 100644 index 000000000..70f3794d1 --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromFile/valid-model.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline TestPipeline { + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestFileLoader { + } + + TestExtractor -> TestLoader; +} diff --git a/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromString/invalid-model.jv b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromString/invalid-model.jv new file mode 100644 index 000000000..7abf8d0f8 --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromString/invalid-model.jv @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline TestPipeline { + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestFileLoader { + } + sta + + TestExtractor -> TestLoader; +} diff --git a/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromString/valid-model.jv b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromString/valid-model.jv new file mode 100644 index 000000000..70f3794d1 --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/extractDocumentFromString/valid-model.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline TestPipeline { + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestFileLoader { + } + + TestExtractor -> TestLoader; +} diff --git a/libs/interpreter-lib/test/assets/parsing-util/validateDocument/invalid-wrong-loader-type.jv b/libs/interpreter-lib/test/assets/parsing-util/validateDocument/invalid-wrong-loader-type.jv new file mode 100644 index 000000000..037e75012 --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/validateDocument/invalid-wrong-loader-type.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline TestPipeline { + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestTableLoader { + } + + TestExtractor -> TestLoader; +} diff --git a/libs/interpreter-lib/test/assets/parsing-util/validateDocument/valid-document.jv b/libs/interpreter-lib/test/assets/parsing-util/validateDocument/valid-document.jv new file mode 100644 index 000000000..70f3794d1 --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/validateDocument/valid-document.jv @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline TestPipeline { + + block TestExtractor oftype TestFileExtractor { + } + + block TestLoader oftype TestFileLoader { + } + + TestExtractor -> TestLoader; +} diff --git a/libs/interpreter-lib/test/assets/parsing-util/validateDocument/valid-simplify-warning.jv b/libs/interpreter-lib/test/assets/parsing-util/validateDocument/valid-simplify-warning.jv new file mode 100644 index 000000000..f7116f9ae --- /dev/null +++ b/libs/interpreter-lib/test/assets/parsing-util/validateDocument/valid-simplify-warning.jv @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg +// +// SPDX-License-Identifier: AGPL-3.0-only + +pipeline TestPipeline { + + block TestExtractor oftype TestFileExtractor { + } + + block TestPropertyBlock oftype TestProperty { + textProperty: "Test"; + integerProperty: 20 + 20; + } + + block TestLoader oftype TestTableLoader { + } + + TestExtractor -> TestPropertyBlock -> TestLoader; +}