blueshell
Version:
A Behavior Tree implementation in modern Javascript
226 lines • 14.1 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Created by josh on 1/10/16.
*/
const chai_1 = require("chai");
const lib_1 = require("../../lib");
const Behavior = __importStar(require("../../lib"));
class TestState {
constructor() {
this.calledMap = new Map();
this.runCounter = 0;
}
}
class LatchedAction extends Behavior.Action {
constructor(name, numRunning = 0, retVal = lib_1.rc.SUCCESS) {
super(name);
this.numRunning = numRunning;
this.retVal = retVal;
this.runCounter = 0;
}
onEvent(state) {
this.runCounter++;
state.runCounter = this.runCounter;
if (this.runCounter < this.numRunning) {
return lib_1.rc.RUNNING;
}
else {
state.calledMap.set(this.retVal, true);
return this.retVal;
}
}
resetCounter() {
this.runCounter = 0;
}
}
describe('LatchedIfElse', function () {
let state;
beforeEach(function () {
state = new TestState();
});
context('conditional is true', function () {
it('should return success (consequent) when conditional is true with no alternative (1x)', function () {
const successAction = new LatchedAction('testLatchedAction', 1, lib_1.rc.SUCCESS);
const ifElse = new Behavior.LatchedIfElse('testLatchedIfElse', (state) => {
return state.runCounter === 0;
}, successAction);
let res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.SUCCESS, 'Behavior Tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Expected Action was not called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
successAction.resetCounter();
state.calledMap.clear();
state.runCounter = 0;
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, '2nd behavior tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Expected Action was not called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
});
it('should return success (consequent) when conditional is true with alternative (2x)', function () {
const successAction = new LatchedAction('testLatchedAction', 2, lib_1.rc.SUCCESS);
const ifElse = new Behavior.LatchedIfElse('testLatchedIfElse', (state) => {
return state.runCounter === 0;
}, successAction, new LatchedAction('testLatchedActionFailure', 1, lib_1.rc.FAILURE));
let res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.RUNNING, 'Behavior Tree not running');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, '2nd Behavior Tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 2, 'Run counter was not incremented');
successAction.resetCounter();
state.calledMap.clear();
state.runCounter = 0;
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.RUNNING, '3rd Behavior Tree not running');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, 'Behavior Tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 2, 'Run counter was not incremented');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, '4th behavior tree not success');
});
it('should restart latching if resetNodeStorage is called', function () {
const successAction = new LatchedAction('testLatchedAction', 2, lib_1.rc.SUCCESS);
const ifElse = new Behavior.LatchedIfElse('testLatchedIfElse', (state) => {
return state.runCounter === 0;
}, successAction, new LatchedAction('testLatchedActionFailure', 1, lib_1.rc.FAILURE));
let res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.RUNNING, 'Behavior Tree not running');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
ifElse.resetNodeStorage(state);
successAction.resetCounter();
state.runCounter = 0;
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.RUNNING, '2nd Behavior Tree not running');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, '3rd Behavior Tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 2, 'Run counter was not incremented');
});
});
context('conditional is false', function () {
it('should return failure when conditional is false and there is no alternative', function () {
const ifElse = new Behavior.IfElse('testIfElse', () => false, new LatchedAction('testLatchedAction', 1, lib_1.rc.SUCCESS));
const state = new TestState();
const res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.FAILURE, 'Behavior Tree not failure');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
});
it('should return failure (alternative) when conditional is false with an alternative rc', function () {
const ifElse = new Behavior.LatchedIfElse('testIfElse', () => false, new LatchedAction('testLatchedAction', 1, lib_1.rc.SUCCESS), lib_1.rc.FAILURE);
const state = new TestState();
const res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.FAILURE, 'Behavior Tree not failure');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 0, 'Run counter was incremented');
});
it('should return success (alternative) when conditional is false with an alternative node (1x)', function () {
const successAction = new LatchedAction('testLatchedAction', 1, lib_1.rc.SUCCESS);
const ifElse = new Behavior.LatchedIfElse('testLatchedIfElse', (state) => {
return state.runCounter !== 0;
}, new LatchedAction('testLatchedActionFailure', 1, lib_1.rc.FAILURE), successAction);
let res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.SUCCESS, 'Behavior Tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Expected Action was not called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
successAction.resetCounter();
state.calledMap.clear();
state.runCounter = 0;
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, '2nd behavior tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Expected Action was not called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
});
it('should return success (alternative) when conditional is false with an alternative node (2x)', function () {
const successAction = new LatchedAction('testLatchedAction', 2, lib_1.rc.SUCCESS);
const ifElse = new Behavior.LatchedIfElse('testLatchedIfElse', (state) => {
return state.runCounter !== 0;
}, new LatchedAction('testLatchedActionFailure', 1, lib_1.rc.FAILURE), successAction);
let res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.RUNNING, 'Behavior Tree not running');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, '2nd Behavior Tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 2, 'Run counter was not incremented');
successAction.resetCounter();
state.calledMap.clear();
state.runCounter = 0;
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.notOk(state.errorReason);
chai_1.assert.equal(res, lib_1.rc.RUNNING, '3rd Behavior Tree not running');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 1, 'Run counter was not incremented');
res = ifElse.handleEvent(state, 'testEvent');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, 'Behavior Tree not success');
chai_1.assert.isTrue(state.calledMap.get(lib_1.rc.SUCCESS), 'Unexpected Action was called');
chai_1.assert.isUndefined(state.calledMap.get(lib_1.rc.FAILURE), 'Unexpected Action was called');
chai_1.assert.strictEqual(state.runCounter, 2, 'Run counter was not incremented');
chai_1.assert.equal(res, lib_1.rc.SUCCESS, '4th behavior tree not success');
});
});
});
//# sourceMappingURL=LatchedIfElse.test.js.map