es-vm
Version:
A visual machine run in ES env like Node/Browser
302 lines (222 loc) • 6.8 kB
JavaScript
const assert = require('assert');
const pack = require('./pack');
pack(({ESVM, Statement}) => describe('Kernel::', function () {
const statement = new Statement();
statement.execute = function* ($) {
yield $.vm.flag = 1;
return 'RET';
};
describe('Method::', function () {
it('get position', function() {
const vm = new ESVM();
assert.equal(null, vm.getPosition);
const statement = new Statement();
vm.pushOperation(statement);
assert.equal(statement.position, vm.getPosition);
});
it('$clearOperationStack', function () {
const vm = new ESVM();
const statement = new Statement();
vm.pushOperation(statement);
assert.equal(statement, vm.$operationStack[0]);
vm.$clearOperationStack();
assert.equal(vm.$operationStack.length, 0);
});
it('pushOperation', function () {
const vm = new ESVM();
const statement = new Statement();
vm.pushOperation(statement);
assert.equal(statement, vm.$operationStack[0]);
});
it('popOperation', function () {
const vm = new ESVM();
const statement = new Statement();
vm.pushOperation(statement);
assert.equal(statement, vm.$operationStack[0]);
assert.equal(vm.popOperation(), statement);
});
it('setOnFetch', function () {
const vm = new ESVM();
assert.throws(() => {
vm.setOnFetch();
}, '[ESVM-DEV]: Need a funtion for vm.setOnFetch.');
assert.equal(vm.setOnFetch(() => {}), vm);
});
describe('fetch::', function () {
this.timeout(5000);
const testStatement = new Statement();
testStatement.execute = function* ($) {
const signal = $.vm.fetch({ type: 'remote' }, 400);
assert.equal(signal, 'VM::BLOCKED');
yield signal;
yield 'after fetch';
};
it('timeout', function (done) {
const vm = new ESVM();
vm.setOnFetch(invoking => {
assert.equal(invoking.type, 'remote');
return new Promise(resolve => {
setTimeout(resolve, 500);
});
});
vm.$loadProgram(testStatement).$launch();
vm.on('error', err => {
assert.equal(err.message, 'Fetching timeout.');
done();
});
});
it('halt without event#program-end', function (done) {
const vm = new ESVM();
vm.setOnFetch(invoking => {
assert.equal(invoking.type, 'remote');
return new Promise(resolve => {
setTimeout(resolve, 500);
});
});
vm.$loadProgram(testStatement).$launch();
setTimeout(() => {
vm.$halt();
}, 300);
setTimeout(() => {
assert.equal(vm.$runtime, null);
done();
}, 400);
vm.on('program-end', $vm => {
assert.equal(vm, $vm);
throw new Error('It was wrong');
});
});
it('rpc with ret', function (done) {
const vm = new ESVM();
const RPCStatement = new Statement();
const mockInvoking = {};
RPCStatement.execute = function* ($) {
const ret = yield $.vm.fetch(mockInvoking, 400);
assert.equal(ret, 'RPC-RET');
};
vm.on('program-end', () => {
done();
});
vm.setOnFetch(invoking => {
assert.equal(invoking, mockInvoking);
return new Promise(resolve => {
setTimeout(()=> resolve('RPC-RET'), 300);
});
});
vm.$loadProgram(RPCStatement).$launch();
});
it('rpc with outter-exception & inner handle.', function (done) {
const vm = new ESVM();
const RPCStatement = new Statement();
const mockInvoking = {};
RPCStatement.execute = function* ($) {
try {
yield $.vm.fetch(mockInvoking, 400);
} catch (err) {
assert.equal(err.message.match('RPC-ERROR') !== null, true);
}
return 'success';
};
vm.on('program-end', (err, ret, $vm) => {
assert.equal(err, null);
assert.equal(ret, 'success');
assert.equal($vm, vm);
done();
});
vm.setOnFetch(invoking => {
assert.equal(invoking, mockInvoking);
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('RPC-ERROR')), 300);
});
});
vm.on('error', function () {
throw new Error('It was wrong');
});
vm.$loadProgram(RPCStatement).$launch();
});
it('rpc with outer-exception but no-handling', function (done) {
const outterError = new Error('RPC-ERROR');
const vm = new ESVM();
const RPCStatement = new Statement();
const mockInvoking = {};
RPCStatement.execute = function* ($) {
yield $.vm.fetch(mockInvoking, 400);
};
vm.on('program-end', (err, ret, $vm) => {
assert.equal(err, outterError);
assert.equal(ret, undefined);
assert.equal($vm, vm);
done();
});
vm.setOnFetch(invoking => {
assert.equal(invoking, mockInvoking);
return new Promise((_, reject) => {
setTimeout(reject(outterError), 300);
});
});
vm.on('error', function (err) {
assert.equal(err.message.match('RPC-ERROR') !== null, true);
});
vm.$loadProgram(RPCStatement).$launch();
});
});
it('$loadProgram', function () {
const vm = new ESVM();
assert.throws(() => {
vm.$loadProgram();
}, '[ESVM-DEV]: Invalid statement.');
vm.$loadProgram(statement);
assert.notEqual(vm.$runtime, null);
});
it('$launch', function (done) {
const vm = new ESVM();
assert.throws(() => {
vm.$launch();
}, '[ESVM]: No program in vm. Use vm.$loadProgram before.');
vm.$loadProgram(statement);
vm.on('program-start', ($vm) => {
assert.equal(vm, $vm);
done();
});
// vm.on('writeback', console.log);
vm.$launch();
});
describe('$run::', function () {
it('get VM::BLOCKED', function () {
const blocked = new Statement();
blocked.execute = function* () {
yield '123';
yield 'VM::BLOCKED';
};
const vm = new ESVM();
const ret = vm.$loadProgram(blocked).$launch();
assert.equal('suspend', ret);
});
it('inner-exception', function (done) {
const exception = new Statement();
exception.execute = function* (test) {
yield 1;
if (test) {
throw new Error('for test');
}
yield 'VM::BLOCKED';
};
const vm = new ESVM();
vm.on('error', function (err) {
assert.equal(err.message, 'for test');
});
vm.on('program-end', function () {
done();
});
vm.$loadProgram(exception).$launch();
});
});
it('$complete', function (done) {
const vm = new ESVM();
vm.on('program-end', function () {
done();
});
vm.$complete();
});
});
}));