import { createConnection , Diagnostic , DiagnosticSeverity , Position , Range , TextDocuments , DidOpenTextDocumentParams , DidOpenTextDocumentNotification } from 'vscode-languageserver/node' ; import { TextDocument } from 'vscode-languageserver-textdocument' ; import * as vscode from 'vscode' ; import { Uri , workspace } from 'vscode' ; import * as path from 'path' ; import * as assert from 'assert' ; import { beforeEach } from 'mocha' ; import { Duplex } from 'stream' ; import { ANTLRBackend } from '../compiling/ANTLRBackend' ; const testFolderLocation = '../../src/test/test-files/ANTLRCompiler.test' ; const TEST_LANGUAGE_ID = 'typescript' ; class TestStream extends Duplex { _write ( chunk , _encoding , done ) { this . emit ( 'data' , chunk ) ; done ( ) ; } _read ( _size ) { } } const up = new TestStream ( ) ; const down = new TestStream ( ) ; const server = createConnection ( up , down ) ; const client = createConnection ( down , up ) ; server . listen ( ) ; client . listen ( ) ; function mockOpenDocNotif ( config ) { const { version , uri , text } = config ; return { textDocument : { uri , languageId : TEST_LANGUAGE_ID , version , text } } ; } function sleep ( ms ) { return new Promise ( ( resolve ) => { setTimeout ( resolve , ms ) ; } ) ; } const filePath = path . join ( __dirname , testFolderLocation , 'single_error.sv' ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : 'Basic testing text!!!' } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; let documents ; suite ( 'ANTLRBackend Tests' , ( ) => { beforeEach ( ( ) => { documents = new TextDocuments ( TextDocument ) ; documents . listen ( server ) ; } ) ; test ( 'test #1: Diagnostics for single syntax error' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'single_error.sv' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( document ) . then ( ( result ) => { const collection = result . get ( document . uri ) ; assert . strictEqual ( collection . length , 1 ) ; collection . forEach ( ( diagnostic ) => { if ( diagnostic . severity !== DiagnosticSeverity . Error ) { assert . fail ( ) ; } } ) ; } , ( error ) => { assert . fail ( ) ; } ) ; } ) . timeout ( 10000 ) ; test ( 'test #2: Diagnostics for multiple syntax errors' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'several_error.sv' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( document ) . then ( ( result ) => { const collection = result . get ( document . uri ) ; assert . strictEqual ( collection . length , 3 ) ; collection . forEach ( ( diagnostic ) => { if ( diagnostic . severity !== DiagnosticSeverity . Error ) { assert . fail ( ) ; } } ) ; } , ( error ) => { assert . fail ( ) ; } ) ; } ) . timeout ( 10000 ) ; test ( 'test #3: Diagnostics for correct code' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'correct.sv' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( document ) . then ( ( result ) => { const collection = result . get ( document . uri ) ; assert . strictEqual ( collection . length , 0 ) ; } , ( error ) => { assert . fail ( ) ; } ) ; } ) . timeout ( 10000 ) ; test ( 'test #4: Diagnostics for empty document' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'empty.sv' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( document ) . then ( ( result ) => { const collection = result . get ( document . uri ) ; assert . strictEqual ( collection . length , 0 ) ; } , ( error ) => { assert . fail ( ) ; } ) ; } ) . timeout ( 10000 ) ; test ( 'test #5: Diagnostics for a document containing unicode characters' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'unicode.sv' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( document ) . then ( ( result ) => { const collection = result . get ( document . uri ) ; assert . strictEqual ( collection . length , 2 ) ; collection . forEach ( ( diagnostic ) => { if ( diagnostic . severity !== DiagnosticSeverity . Error ) { assert . fail ( ) ; } } ) ; } , ( error ) => { assert . fail ( ) ; } ) ; } ) . timeout ( 10000 ) ; test ( 'test #6: Diagnostics for verilog document' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'single_error.v' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( document ) . then ( ( result ) => { const collection = result . get ( document . uri ) ; assert . strictEqual ( collection . length , 1 ) ; collection . forEach ( ( diagnostic ) => { if ( diagnostic . severity !== DiagnosticSeverity . Error ) { assert . fail ( ) ; } } ) ; } , ( error ) => { assert . fail ( ) ; } ) ; } ) . timeout ( 10000 ) ; test ( 'test #7: Diagnostics for non-Verilog/SystemVerilog document' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'single_error.txt' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( document ) . then ( ( result ) => { assert . fail ( ) ; } , ( error ) => { } ) ; } ) . timeout ( 10000 ) ; test ( 'test #8: Diagnostics for invalid document with open document' , async ( ) => { const filePath = path . join ( __dirname , testFolderLocation , 'single_error.sv' ) ; const uriDoc = Uri . file ( filePath ) ; const documentWorkspace = await workspace . openTextDocument ( uriDoc ) ; const document = castTextDocument ( documentWorkspace ) ; const openDocNotif = mockOpenDocNotif ( { version : 1 , uri : filePath , text : document . getText ( ) } ) ; client . sendNotification ( DidOpenTextDocumentNotification . type , openDocNotif ) ; while ( documents . keys ( ) . length === 0 ) await sleep ( 10 ) ; const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( undefined ) . then ( ( result ) => { assert . fail ( ) ; } , ( error ) => { } ) ; } ) . timeout ( 10000 ) ; test ( 'test #9: Diagnostics for invalid document without open document' , async ( ) => { const documentCompiler = new ANTLRBackend ( ) ; await documentCompiler . getDiagnostics ( undefined ) . then ( ( result ) => { assert . fail ( ) ; } , ( error ) => { } ) ; } ) . timeout ( 10000 ) ; } ) ; param document returns function castTextDocument ( document ) { return { uri : document . uri . fsPath , languageId : document . languageId , version : document . version , getText ( range ? ) { if ( range ) return document . getText ( castRange ( range ) ) ; return document . getText ( ) ; } , lineCount : document . lineCount , positionAt ( offset ) { const position = document . positionAt ( offset ) ; return { line : position . line , character : position . character } ; } , offsetAt ( position ) { return document . offsetAt ( castPosition ( position ) ) ; } } ; } param document returns function castRange ( range ) { const startOld = range . start ; const endOld = range . end ; const start = new vscode . Position ( startOld . line , startOld . character ) ; const end = new vscode . Position ( endOld . line , endOld . character ) ; return new vscode . Range ( start , end ) ; } param document returns function castPosition ( position ) { return new vscode . Position ( position . line , position . character ) ; }