diff --git a/clients/cobol-lsp-vscode-extension/src/test/suite/lsp.spec.xmlgenerate.test.ts b/clients/cobol-lsp-vscode-extension/src/test/suite/lsp.spec.xmlgenerate.test.ts new file mode 100644 index 0000000000..64e8c12606 --- /dev/null +++ b/clients/cobol-lsp-vscode-extension/src/test/suite/lsp.spec.xmlgenerate.test.ts @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2025 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +import * as assert from "assert"; +import * as helper from "./testHelper"; +import { pos } from "./testHelper"; +import * as vscode from "vscode"; +import * as path from "path"; + +suite("TF48417: XML GENERATE", function () { + let editor: vscode.TextEditor; + suiteSetup(async function () { + this.timeout(0); + this.slow(2000); + await helper.updateConfig("basic.json"); + await helper.activate(); + }); + + this.afterEach(async () => await helper.closeAllEditors()).timeout( + helper.TEST_TIMEOUT, + ); + + this.afterAll(async () => await helper.closeAllEditors()).timeout( + helper.TEST_TIMEOUT, + ); + + test("TC369351: Identifier1 must be alphanumeric", async () => { + const extSrcPath = path.join("TEST2.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST2.CBL"); + let diagnostics = await diagPromise; + await helper.insertString( + editor, + pos(19, 0), + " 01 XML-DOC123 PIC X(5000) USAGE NATIONAL.\n", + ); + await helper.deleteLine(editor, 23); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369351: identifier1 must be category national, national group", async () => { + const extSrcPath = path.join("TEST2.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST2.CBL"); + let diagnostics = await diagPromise; + await helper.insertString( + editor, + pos(19, 0), + " 01 XML-DOC123 PIC X(5000) USAGE NATIONAL.\n" + + " 01 REQUEST GROUP-USAGE NATIONAL.\n" + + " 06 ROUTE.\n" + + " 11 NAME PIC X(030).\n" + + " 11 VERSION PIC 9(004).\n" + ); + await helper.deleteLine(editor, 27); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369351: Identifier1 must not overlap identifier2, identifier3, identifier4, identifier5.", async () => { + const extSrcPath = path.join("TEST2.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST2.CBL"); + let diagnostics = await diagPromise; + await helper.deleteLine(editor, 22); + await helper.insertString( + editor, + pos(19, 0), + " 01 OutputXml.\n" + + " 05 TestXmlTag PIC X(20).\n" + ); + await helper.insertString( + editor, + pos(23, 0), + " XML GENERATE OutputXml FROM TestXmlTag\n" + + " END-XML.\n" + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 1, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 1); + const message = diagnostics[0].message; + assert.match(message, /^XML generate TESTXMLTAG must not overlap OUTPUTXML/); + await helper.deleteLine(editor, 19); + await helper.deleteLine(editor, 20); + await helper.insertString( + editor, + pos(19, 0), + " 01 TestXmlTag PIC X(20).\n" + + " 01 OutputXml PIC X(100).\n" + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369352: identifier2 references a national group item", async () => { + const extSrcPath = path.join("TEST14.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST14.CBL"); + let diagnostics = await diagPromise; + await helper.insertString( + editor, + pos(10, 0), + " 01 WS-ORDERS GROUP-USAGE NATIONAL.\n" + + " 05 WS-ORDER OCCURS 2.\n" + + " 10 WS-DATA usage NATIONAL PIC X(4096).\n" + + " 01 WS-ORDERS.\n" + + " 05 WS-ORDER OCCURS 2.\n" + + " 10 WS-DATA USAGE NATIONAL PIC X(4096).\n" + ); + await helper.deleteLine(editor, 22); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369352: identifier2 must not overlap identifier1,or identifier3", async () => { + const extSrcPath = path.join("TEST14.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST14.CBL"); + let diagnostics = await diagPromise; + await helper.deleteLine(editor, 16); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.deleteLine(editor, 8); + await helper.deleteLine(editor, 6); + await helper.insertString( + editor, + pos(6, 0), + " 05 DOC PIC X(512)." + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 1, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 1); + const message = diagnostics[0].message; + assert.match(message, /^XML generate GREET must not overlap DOC/); + await helper.sleep(5000); + }); + + test("TC369354: must not overlap identifier1, identifier2, identifier4, or identifier5", async () => { + const extSrcPath = path.join("TEST14.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST14.CBL"); + let diagnostics = await diagPromise; + await helper.deleteLine(editor, 16); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.deleteLine(editor, 9); + await helper.deleteLine(editor, 7); + await helper.insertString( + editor, + pos(7, 0), + " 05 DOC-LENGTH PIC 9(05)." + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 1, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 1); + const message = diagnostics[0].message; + assert.match(message, /^XML generate DOC-LENGTH must not overlap GREET/); + await helper.sleep(5000); + }); + + test("TC369355: COUNT IN phrase, " + + "TC369360: NAMESPACE and NAMESPACE-PREFIX phrases", async () => { + const extSrcPath = path.join("TEST14.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST14.CBL"); + let diagnostics = await diagPromise; + await helper.deleteLine(editor, 16); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369356: ENCODING phrase without codepage", async () => { + const extSrcPath = path.join("TEST61.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST61.CBL"); + await helper.deleteLine(editor, 11); + await helper.insertString( + editor, + pos(11, 0), + " WITH ENCODING" + ); + let diagnostics = await diagPromise; + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 1, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 1); + await helper.sleep(5000); + }); + + test("TC369358: XML-DECLARATION phrase", async () => { + const extSrcPath = path.join("TEST61.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST61.CBL"); + await helper.deleteLine(editor, 11); + await helper.deleteLine(editor, 12); + let diagnostics = await diagPromise; + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 1, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 1); + await helper.insertString( + editor, + pos(11, 0), + " WITH XML-DECLARATION." + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369359: ATTRIBUTES phrase", async () => { + const extSrcPath = path.join("TEST51.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST51.CBL"); + await helper.deleteLine(editor, 12); + let diagnostics = await diagPromise; + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 1, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 1); + await helper.insertString( + editor, + pos(12, 0), + " 01 XML-OUT PIC X(200)." + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369361: NAME phrase", async () => { + const extSrcPath = path.join("TEST15.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST15.CBL"); + await helper.deleteLine(editor, 10); + let diagnostics = await diagPromise; + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 2, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 2); + await helper.insertString( + editor, + pos(10, 0), + " 05 abc PIC x(3) value spaces." + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369362: TYPE phrase", async () => { + const extSrcPath = path.join("TEST16.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST16.CBL"); + await helper.deleteLine(editor, 8); + let diagnostics = await diagPromise; + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 1, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 1); + await helper.insertString( + editor, + pos(8, 0), + " 01 Doc pic X(500)." + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); + + test("TC369363: SUPPRESS, generic-suppression-phrase, ON EXCEPTION, NOT ON EXCEPTION phrase", async () => { + const extSrcPath = path.join("TEST10.CBL"); + const diagPromise = helper.waitForDiagnosticsChange(extSrcPath); + await helper.showDocument(extSrcPath); + const editor = helper.getEditor("TEST10.CBL"); + await helper.deleteLine(editor, 16); + let diagnostics = await diagPromise; + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 3, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 3); + await helper.insertString( + editor, + pos(16, 0), + " 01 OUTPUT-XML PIC X(5000)." + ); + await helper.waitFor( + () => vscode.languages.getDiagnostics(editor.document.uri).length === 0, + ); + diagnostics = vscode.languages.getDiagnostics(editor.document.uri); + assert.strictEqual(diagnostics.length, 0); + await helper.sleep(5000); + }); +}); diff --git a/tests/test_files/project/TEST10.CBL b/tests/test_files/project/TEST10.CBL new file mode 100644 index 0000000000..a022186a66 --- /dev/null +++ b/tests/test_files/project/TEST10.CBL @@ -0,0 +1,47 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID. TEST10. + DATA DIVISION. + WORKING-STORAGE SECTION. + + 01 GrpHdr. + 02 A1. + 03 MsgId PIC X(50) VALUE SPACES. + 03 Test3. + 05 Test31. + 07 Test32 PIC X(10) VALUE SPACES. + 05 Test4. + 07 Test5. + 09 Test6. + 11 Test7 PIC X(10) VALUE SPACES. + + 01 OUTPUT-XML PIC X(5000). + + PROCEDURE DIVISION. + MAIN-PARA. + + MOVE 'MESSAGE ID' TO MsgId. + MOVE 'TEST32' TO Test32. + MOVE SPACES TO Test7. + + INITIALIZE OUTPUT-XML. + + * XML GENERATE OUTPUT-XML from Grphdr + * SUPPRESS Test31 EVERY NONUMERIC ELEMENT WHEN SPACES + * ON EXCEPTION + * DISPLAY 'GENERATE XML Error-Header' + * NOT ON EXCEPTION + * CONTINUE + * END-XML + + XML GENERATE OUTPUT-XML from Grphdr + SUPPRESS EVERY NONNUMERIC ELEMENT WHEN SPACES + ON EXCEPTION + DISPLAY 'GENERATE XML Error-Header' + NOT ON EXCEPTION + CONTINUE + END-XML + + DISPLAY 'OUTPUT:' OUTPUT-XML . + + MAIN-EXIT. + EXIT. \ No newline at end of file diff --git a/tests/test_files/project/TEST14.CBL b/tests/test_files/project/TEST14.CBL new file mode 100644 index 0000000000..da27a14997 --- /dev/null +++ b/tests/test_files/project/TEST14.CBL @@ -0,0 +1,28 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID. TEST14. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 GREET. + 05 GREETMSG PIC X(80) VALUE 'Hello !!'. + * 05 DOC PIC X(512). + * 05 DOC-LENGTH PIC 9(05). + 01 DOC PIC X(512). + 01 DOC-LENGTH PIC 9(05). + + * NAMESPACE AND PREFIX + 01 NSPACE PIC X(20) VALUE 'http://example'. + 01 NPREFIX PIC X(5) VALUE 'pre'. + + PROCEDURE DIVISION. + MOVE 0 TO XYZ-ID. + * GENERATE THE XML VALIDATES OUTPUT AND ENCODING. + XML GENERATE DOC FROM GREET + COUNT IN DOC-LENGTH + + WITH ENCODING 1208 + NAMESPACE IS NSPACE + NAMESPACE-PREFIX IS NPREFIX + ON EXCEPTION + DISPLAY 'ERROR IN GENERATE XML:' XML-CODE + END-XML. + STOP RUN. \ No newline at end of file diff --git a/tests/test_files/project/TEST15.CBL b/tests/test_files/project/TEST15.CBL new file mode 100644 index 0000000000..2884d89ad0 --- /dev/null +++ b/tests/test_files/project/TEST15.CBL @@ -0,0 +1,22 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 x PIC X(200). + 01 y. + 03 z PIC X(15) VALUE "hello, world!". + 03 az PIC X(15) VALUE "goodbye, world!". + 03 ab. + 05 abc PIC x(3) value spaces. + + PROCEDURE DIVISION. + XML GENERATE x + FROM y + WITH XML-DECLARATION + NAME OF abc IS "ABCDEF", z IS "zeta" + TYPE OF z IS ATTRIBUTE + SUPPRESS WHEN SPACES + + DISPLAY FUNCTION TRIM(x) + . \ No newline at end of file diff --git a/tests/test_files/project/TEST16.CBL b/tests/test_files/project/TEST16.CBL new file mode 100644 index 0000000000..2953aaacd0 --- /dev/null +++ b/tests/test_files/project/TEST16.CBL @@ -0,0 +1,17 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID TEST16. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 Msg. + 02 Msg-Severity pic 9 value 1. + 02 Msg-Date pic 9999/99/99 value "2012/04/12". + 02 Msg-Text pic X(50) value "Sell everything!". + 01 Doc pic X(500). + + PROCEDURE DIVISION. + XML Generate Doc from Msg + With attributes + Type of Msg-Severity is attribute + Msg-Date is attribute + Msg-Text is element + End-XML. \ No newline at end of file diff --git a/tests/test_files/project/TEST51.CBL b/tests/test_files/project/TEST51.CBL new file mode 100644 index 0000000000..ffaa0875b4 --- /dev/null +++ b/tests/test_files/project/TEST51.CBL @@ -0,0 +1,16 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID TEST3. + DATA DIVISION. + WORKING-STORAGE SECTION. + + 01 XML-INPUT. + 05 NAME PIC X(10) VALUE "JANE". + 05 SALARY. + 10 BASIC PIC X(5) VALUE "10000". + 10 HRA PIC X(3) VALUE "2000". + 05 DEPT PIC X(3) VALUE "SALES". + + 01 XML-OUT PIC X(200). + + PROCEDURE DIVISION. + XML GENERATE XML-OUT FROM XML-INPUT WITH ATTRIBUTES. diff --git a/tests/test_files/project/TEST61.CBL b/tests/test_files/project/TEST61.CBL new file mode 100644 index 0000000000..5def76c482 --- /dev/null +++ b/tests/test_files/project/TEST61.CBL @@ -0,0 +1,13 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID TEST3. + DATA DIVISION. + WORKING-STORAGE SECTION. + + 01 MSGS. + 05 MSG PIC X(80) VALUE 'Hello world!'. + 01 OUT PIC X(200). + + PROCEDURE DIVISION. + XML GENERATE OUT FROM MSGS + WITH ENCODING 1200 + WITH XML-DECLARATION. \ No newline at end of file