diff --git a/src/integration-tests/miparser.spec.ts b/src/integration-tests/miparser.spec.ts new file mode 100644 index 00000000..07d705c8 --- /dev/null +++ b/src/integration-tests/miparser.spec.ts @@ -0,0 +1,157 @@ +/********************************************************************* + * Copyright (c) 2023 Kichwa Coders Canada Inc. and others + * + * 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 + *********************************************************************/ + +import { GDBBackend } from '../GDBBackend'; +import { MIParser } from '../MIParser'; +import * as sinon from 'sinon'; +import { logger } from '@vscode/debugadapter/lib/logger'; + +describe('MI Parser Test Suite', function () { + let gdbBackendMock: sinon.SinonStubbedInstance; + let loggerErrorSpy: sinon.SinonSpy; + let parser: MIParser; + + beforeEach(async function () { + gdbBackendMock = sinon.createStubInstance(GDBBackend); + loggerErrorSpy = sinon.spy(logger, 'error'); + + parser = new MIParser(gdbBackendMock); + }); + + afterEach(function () { + try { + sinon.assert.notCalled(loggerErrorSpy); + } finally { + sinon.restore(); + } + }); + + it('simple result-record', async function () { + const callback = sinon.spy(); + parser.queueCommand(5, callback); + parser.parseLine('5^done'); + sinon.assert.calledOnceWithExactly(callback, 'done', {}); + }); + + it('simple result-record with multi-digit token', async function () { + const callback = sinon.spy(); + parser.queueCommand(1234, callback); + parser.parseLine('1234^done'); + sinon.assert.calledOnceWithExactly(callback, 'done', {}); + }); + + it('simple result-record for unknown token number', async function () { + parser.parseLine('5^done'); + sinon.assert.calledOnceWithExactly( + loggerErrorSpy, + 'GDB response with no command: 5' + ); + loggerErrorSpy.resetHistory(); + }); + + it('simple result-record for no token number', async function () { + parser.parseLine('^done'); + sinon.assert.calledOnceWithExactly( + loggerErrorSpy, + 'GDB response with no command: ' + ); + loggerErrorSpy.resetHistory(); + }); + + it('simple console-stream-output', async function () { + parser.parseLine('~"message"'); + sinon.assert.calledOnceWithExactly( + gdbBackendMock.emit as sinon.SinonStub, + 'consoleStreamOutput', + 'message', + 'stdout' + ); + }); + + it('simple target-stream-output', async function () { + parser.parseLine('@"message"'); + sinon.assert.calledOnceWithExactly( + gdbBackendMock.emit as sinon.SinonStub, + 'consoleStreamOutput', + 'message', + 'stdout' + ); + }); + + it('simple log-stream-output', async function () { + parser.parseLine('&"message"'); + sinon.assert.calledOnceWithExactly( + gdbBackendMock.emit as sinon.SinonStub, + 'consoleStreamOutput', + 'message', + 'log' + ); + }); + + it('simple notify-async-output', async function () { + parser.parseLine('=message,object={value="1234"}'); + sinon.assert.calledOnceWithExactly( + gdbBackendMock.emit as sinon.SinonStub, + 'notifyAsync', + 'message', + { + object: { + value: '1234', + }, + } + ); + }); + + it('simple exec-async-output', async function () { + parser.parseLine('*message,object={value="1234"}'); + sinon.assert.calledOnceWithExactly( + gdbBackendMock.emit as sinon.SinonStub, + 'execAsync', + 'message', + { + object: { + value: '1234', + }, + } + ); + }); + + it('simple status-async-output', async function () { + parser.parseLine('+message,object={value="1234"}'); + sinon.assert.calledOnceWithExactly( + gdbBackendMock.emit as sinon.SinonStub, + 'statusAsync', + 'message', + { + object: { + value: '1234', + }, + } + ); + }); + + it('simple non-MI output', async function () { + // this is when the output line doesn't match any of + // expected output syntax so we just log it back to the + // user. This can happen when the inferior's stdout + // is the same as gdb's stdout. + parser.parseLine('other'); + sinon.assert.calledOnceWithExactly( + gdbBackendMock.emit as sinon.SinonStub, + 'consoleStreamOutput', + // XXX: This tests for how this code has always been implemented, + // but it isn't particularly useful to do this. Fixing it is low + // priority because users should avoid having inferior stdout + // being on the MI stdout as it leads to parsing errors + 'other\n', + 'stdout' + ); + }); +});