Skip to content

Commit

Permalink
Add Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfbecker committed Mar 20, 2016
1 parent 5cfbfdd commit 488c53c
Show file tree
Hide file tree
Showing 14 changed files with 827 additions and 88 deletions.
4 changes: 4 additions & 0 deletions .vscode/tasks.json
Expand Up @@ -12,6 +12,10 @@
{
"taskName": "watch",
"isWatching": true
},
{
"taskName": "test",
"isTestCommand": true
}
]
}
4 changes: 4 additions & 0 deletions package.json
Expand Up @@ -43,11 +43,14 @@
},
"devDependencies": {
"babel-preset-es2015-node4": "^2.0.3",
"chai": "^3.5.0",
"chai-as-promised": "^5.2.0",
"file-url": "^1.1.0",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-sourcemaps": "^1.6.0",
"gulp-typescript": "^2.12.1",
"mocha": "^2.4.5",
"tslint": "^3.6.0",
"typescript": "^1.8.9"
},
Expand All @@ -56,6 +59,7 @@
"compile": "gulp compile",
"watch": "gulp watch",
"start": "code testproject --extensionDevelopmentPath=.",
"test": "mocha out/test --timeout 5000 --slow 1000",
"lint": "tslint -c tslint.json src/**/*.ts"
},
"contributes": {
Expand Down
285 changes: 285 additions & 0 deletions src/test/adapter.ts
@@ -0,0 +1,285 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import * as path from 'path';
import {DebugClient} from './debugClient';
chai.use(chaiAsPromised);
const assert = chai.assert;

describe('PHP Debug Adapter', () => {

const TEST_PROJECT = path.normalize(__dirname + '/../../testproject');

let client: DebugClient;

beforeEach(async () => {
client = new DebugClient('node', path.normalize(__dirname + '/../phpDebug'), 'php');
await client.start();
});

afterEach(() => client.stop());

describe('initialization', () => {

it('should return supported features', async () => {
const response = await client.initializeRequest();
assert.equal(response.body.supportsConfigurationDoneRequest, true);
assert.equal(response.body.supportsEvaluateForHovers, false);
assert.equal(response.body.supportsConditionalBreakpoints, true);
assert.equal(response.body.supportsFunctionBreakpoints, true);
});
});

describe('launch as CLI', () => {

const program = path.join(TEST_PROJECT, 'hello_world.php');

it('should error on non-existing file', () =>
assert.isRejected(client.launch({program: 'thisfiledoesnotexist.php'}))
);

it('should run program to the end', async () => {
await client.launch({program});
await Promise.all([
client.configurationSequence(),
client.waitForEvent('terminated')
]);
});

it('should stop on entry', async () => {
await client.launch({program, stopOnEntry: true});
await Promise.all([
client.configurationSequence(),
client.assertStoppedLocation('entry', {path: program, line: 3})
]);
});
});

describe('breakpoints', () => {

const program = path.join(TEST_PROJECT, 'hello_world.php');

describe('line breakpoints', () => {

it('should stop on a breakpoint', () =>
client.hitBreakpoint({program}, {path: program, line: 4})
);

it('should stop on a breakpoint in file with spaces in its name', () =>
client.hitBreakpoint({program}, {path: program, line: 4})
);

it('should stop on a breakpoint identical to the entrypoint', () =>
client.hitBreakpoint({program}, {path: program, line: 3})
);
});

describe('exception breakpoints', () => {

const program = path.join(TEST_PROJECT, 'error.php');

beforeEach(() => Promise.all([
client.launch({program}),
client.waitForEvent('initialized')
]));

it('should support stopping only on a notice', async () => {
await client.setExceptionBreakpointsRequest({filters: ['Notice']});
await Promise.all([
client.configurationDoneRequest(),
client.assertStoppedLocation('exception', {path: program, line: 6})
]);
await Promise.all([
client.continueRequest({threadId: 1}),
client.waitForEvent('terminated')
]);
});

it('should support stopping only on a warning', async () => {
await client.setExceptionBreakpointsRequest({filters: ['Warning']});
await Promise.all([
client.assertStoppedLocation('exception', {path: program, line: 9}),
client.configurationDoneRequest()
]);
await Promise.all([
client.continueRequest({threadId: 1}),
client.waitForEvent('terminated')
]);
});

it('should support stopping only on an exception', async () => {
await client.setExceptionBreakpointsRequest({filters: ['Exception']});
await Promise.all([
client.configurationDoneRequest(),
client.assertStoppedLocation('exception', {path: program, line: 12})
]);
await Promise.all([
client.continueRequest({threadId: 1}),
client.waitForEvent('terminated')
]);
});

it('should support stopping on everything', async () => {
await client.setExceptionBreakpointsRequest({filters: ['*']});
// Notice
await Promise.all([
client.configurationDoneRequest(),
client.assertStoppedLocation('exception', {path: program, line: 6})
]);
// Warning
await Promise.all([
client.continueRequest({threadId: 1}),
client.assertStoppedLocation('exception', {path: program, line: 9})
]);
// Exception
await Promise.all([
client.continueRequest({threadId: 1}),
client.assertStoppedLocation('exception', {path: program, line: 12})
]);
// Fatal error: uncaught exception
await Promise.all([
client.continueRequest({threadId: 1}),
client.assertStoppedLocation('exception', {path: program, line: 12})
]);
await Promise.all([
client.continueRequest({threadId: 1}),
client.waitForEvent('terminated')
]);
});

it('should report the error in a virtual error scope');
});

describe('conditional breakpoints', () => {

const program = path.join(TEST_PROJECT, 'variables.php');

it('should stop on a conditional breakpoint when condition is true', async () => {
await client.launch({program});
await client.waitForEvent('initialized');
const bp = (await client.setBreakpointsRequest({breakpoints: [{line: 10, condition: '$anInt === 123'}], source: {path: program}})).body.breakpoints[0];
assert.equal(bp.verified, true, 'breakpoint verification mismatch: verified');
assert.equal(bp.line, 10, 'breakpoint verification mismatch: line');
const frame = (await Promise.all([
client.configurationDoneRequest(),
client.assertStoppedLocation('breakpoint', {path: program, line: 10})
]))[1].body.stackFrames[0];
const result = (await client.evaluateRequest({context: 'watch', frameId: frame.id, expression: '$anInt'})).body.result;
assert.equal(result, 123);
});

it('should not stop on a conditional breakpoint when condition is false', async () => {
await client.launch({program});
await client.waitForEvent('initialized');
const bp = (await client.setBreakpointsRequest({breakpoints: [{line: 10, condition: '$anInt !== 123'}], source: {path: program}})).body.breakpoints[0];
assert.equal(bp.verified, true, 'breakpoint verification mismatch: verified');
assert.equal(bp.line, 10, 'breakpoint verification mismatch: line');
await client.configurationDoneRequest();
await client.waitForEvent('terminated');
});
});

describe('function breakpoints', () => {

const program = path.join(TEST_PROJECT, 'function.php');

it('should stop on a function breakpoint', async () => {
await client.launch({program});
await client.waitForEvent('initialized');
const breakpoint = (await client.setFunctionBreakpointsRequest({breakpoints: [{name: 'a_function'}]})).body.breakpoints[0];
assert.strictEqual(breakpoint.verified, true);
await client.configurationDoneRequest();
client.assertStoppedLocation('breakpoint', {path: program, line: 5});
});
});
});

describe('variables', () => {

const program = path.join(TEST_PROJECT, 'variables.php');

it('should report all variables correctly', async () => {
await Promise.all([
client.launch({program}),
client.waitForEvent('initialized')
]);
await client.setBreakpointsRequest({source: {path: program}, breakpoints: [{line: 15}]});
await Promise.all([
client.configurationDoneRequest(),
client.waitForEvent('stopped')
]);
const stackFrame = (await client.stackTraceRequest({threadId: 1})).body.stackFrames[0];
const [localScope, superglobalsScope, constantsScope] = (await client.scopesRequest({frameId: stackFrame.id})).body.scopes;

const variables = (await client.variablesRequest({variablesReference: localScope.variablesReference})).body.variables;
assert.lengthOf(variables, 9);

const [aBoolean, aFloat, aLargeArray, aString, anArray, anEmptyString, anInt, nullValue, variableThatsNotSet] = variables;

assert.propertyVal(aBoolean, 'name', '$aBoolean');
assert.propertyVal(aBoolean, 'value', 'true');
assert.propertyVal(aFloat, 'name', '$aFloat');
assert.propertyVal(aFloat, 'value', '1.23');
assert.propertyVal(aString, 'name', '$aString');
assert.propertyVal(aString, 'value', '"123"');
assert.propertyVal(anEmptyString, 'name', '$anEmptyString');
assert.propertyVal(anEmptyString, 'value', '""');
assert.propertyVal(anInt, 'name', '$anInt');
assert.propertyVal(anInt, 'value', '123');
assert.propertyVal(nullValue, 'name', '$nullValue');
assert.propertyVal(nullValue, 'value', 'null');
assert.propertyVal(variableThatsNotSet, 'name', '$variableThatsNotSet');
assert.propertyVal(variableThatsNotSet, 'value', 'uninitialized');

assert.propertyVal(anArray, 'name', '$anArray');
assert.propertyVal(anArray, 'value', 'array(2)');
const items = (await client.variablesRequest({variablesReference: anArray.variablesReference})).body.variables;
assert.lengthOf(items, 2);
assert.propertyVal(items[0], 'name', '0');
assert.propertyVal(items[0], 'value', '1');
assert.propertyVal(items[1], 'name', 'test');
assert.propertyVal(items[1], 'value', '2');

assert.propertyVal(aLargeArray, 'name', '$aLargeArray');
assert.propertyVal(aLargeArray, 'value', 'array(100)');
const largeArrayItems = (await client.variablesRequest({variablesReference: aLargeArray.variablesReference})).body.variables;
assert.lengthOf(largeArrayItems, 100);
assert.propertyVal(largeArrayItems[0], 'name', '0');
assert.propertyVal(largeArrayItems[0], 'value', '"test"');
assert.propertyVal(largeArrayItems[99], 'name', '99');
assert.propertyVal(largeArrayItems[99], 'value', '"test"');

const constants = (await client.variablesRequest({variablesReference: constantsScope.variablesReference})).body.variables;
assert.lengthOf(constants, 1);
assert.propertyVal(constants[0], 'name', 'TEST_CONSTANT');
assert.propertyVal(constants[0], 'value', '123');
});
});

describe('virtual sources', () => {
it('should break on an exception inside eval code');
it('should return the eval code with a source request');
});

describe('parallel requests', () => {
it('should report multiple requests as threads');
});

describe('evaluation', () => {
it('should return the eval result');
it('should return variable references for structured results');
});

describe.skip('output events', () => {

const program = path.join(TEST_PROJECT, 'output.php');

it('stdout and stderr events should be complete and in correct order', async () => {
await Promise.all([
client.launch({program}),
client.configurationSequence()
]);
await client.assertOutput('stdout', 'stdout output 1\nstdout output 2');
await client.assertOutput('stderr', 'stderr output 1\nstderr output 2');
});
});
});

0 comments on commit 488c53c

Please sign in to comment.