behaviortree
Version:
A JavaScript implementation of Behavior Trees. They are useful for implementing AIs. For Browsers and NodeJS.
175 lines (174 loc) • 7.37 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-env jest */
/* eslint-disable @typescript-eslint/no-explicit-any */
const constants_1 = require("./constants");
const ParallelSelector_1 = __importDefault(require("./ParallelSelector"));
const Task_1 = __importDefault(require("./Task"));
describe('ParallelSelector', () => {
let countSuccess = 0;
const successTask = new Task_1.default({
run: function () {
++countSuccess;
return constants_1.SUCCESS;
}
});
let countFail = 0;
const failTask = new Task_1.default({
run: function () {
++countFail;
return constants_1.FAILURE;
}
});
let countRunning = 0;
const runningTask = new Task_1.default({
run: function () {
++countRunning;
return constants_1.RUNNING;
}
});
beforeEach(() => {
countSuccess = 0;
countFail = 0;
countRunning = 0;
});
it('runs all child nodes and returns running child index as long as one node is running and none failing', () => {
const parallelSelector = new ParallelSelector_1.default({
nodes: [successTask, successTask, runningTask]
});
const result = parallelSelector.run();
expect(countRunning).toEqual(1);
expect(countSuccess).toEqual(2);
expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, constants_1.RUNNING] });
});
it('directly sends back failure if one node is failing', () => {
const parallelSelector = new ParallelSelector_1.default({
nodes: [successTask, failTask, runningTask]
});
const result = parallelSelector.run();
expect(countRunning).toEqual(1);
expect(countSuccess).toEqual(1);
expect(countFail).toEqual(1);
expect(result).toEqual(constants_1.FAILURE);
});
it('returns failure if one task is failing', () => {
const parallelSelector = new ParallelSelector_1.default({
nodes: [successTask, failTask]
});
const result = parallelSelector.run();
expect(countSuccess).toEqual(1);
expect(countFail).toEqual(1);
expect(result).toEqual(constants_1.FAILURE);
});
it('returns success if all tasks are success', () => {
const parallelSelector = new ParallelSelector_1.default({
nodes: [successTask, successTask]
});
const result = parallelSelector.run();
expect(countSuccess).toEqual(2);
expect(result).toEqual(constants_1.SUCCESS);
});
describe('running tasks', () => {
const switchTask = new Task_1.default({
run: function (blackboard) {
++blackboard.switchCounter;
return blackboard.switchResult;
}
});
const switchTask2 = new Task_1.default({
run: function (blackboard) {
++blackboard.switchCounter2;
return blackboard.switchResult2;
}
});
const switchTask3 = new Task_1.default({
run: function (blackboard) {
++blackboard.switchCounter3;
return blackboard.switchResult3;
}
});
const parallelSelector = new ParallelSelector_1.default({
nodes: [successTask, successTask, switchTask, switchTask2, switchTask3]
});
it('resumes tasks that where running and stops as soon as one task returns failure', () => {
const blackboard = {
switchCounter: 0,
switchResult: constants_1.RUNNING,
switchCounter2: 0,
switchResult2: constants_1.RUNNING,
switchCounter3: 0,
switchResult3: constants_1.RUNNING
};
let result = parallelSelector.run(blackboard);
expect(countSuccess).toEqual(2);
expect(blackboard.switchCounter).toEqual(1);
expect(blackboard.switchCounter2).toEqual(1);
expect(blackboard.switchCounter3).toEqual(1);
expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, constants_1.RUNNING, constants_1.RUNNING, constants_1.RUNNING] });
blackboard.switchResult2 = constants_1.SUCCESS;
result = parallelSelector.run(blackboard, { lastRun: result });
expect(countSuccess).toEqual(2);
expect(blackboard.switchCounter).toEqual(2);
expect(blackboard.switchCounter2).toEqual(2);
expect(blackboard.switchCounter3).toEqual(2);
expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, constants_1.RUNNING, constants_1.SUCCESS, constants_1.RUNNING] });
blackboard.switchResult = constants_1.FAILURE;
result = parallelSelector.run(blackboard, { lastRun: result });
// counter 2 did not run anymore
expect(blackboard.switchCounter).toEqual(3);
expect(blackboard.switchCounter2).toEqual(2);
expect(blackboard.switchCounter3).toEqual(3);
expect(result).toEqual(constants_1.FAILURE);
});
});
describe('start and end callbacks', () => {
const aTask = new Task_1.default({
run: function () {
return constants_1.SUCCESS;
}
});
const switchTask = new Task_1.default({
start: function (blackboard) {
++blackboard.start;
},
run: function (blackboard) {
++blackboard.run;
return blackboard.switchResult;
},
end: function (blackboard) {
++blackboard.end;
}
});
it('start is not called again on further running node', () => {
const parallelSelector = new ParallelSelector_1.default({
nodes: [aTask, aTask, switchTask, aTask]
});
const blackboard = {
switchResult: constants_1.RUNNING,
start: 0,
run: 0,
end: 0
};
const result = parallelSelector.run(blackboard);
expect(blackboard.start).toEqual(1);
expect(blackboard.run).toEqual(1);
expect(blackboard.end).toEqual(0);
const result2 = parallelSelector.run(blackboard, { lastRun: result, rerun: true });
expect(blackboard.start).toEqual(1);
expect(blackboard.run).toEqual(2);
expect(blackboard.end).toEqual(0);
blackboard.switchResult = constants_1.SUCCESS;
parallelSelector.run(blackboard, { lastRun: result2, rerun: true });
expect(blackboard.start).toEqual(1);
expect(blackboard.run).toEqual(3);
expect(blackboard.end).toEqual(1);
parallelSelector.run(blackboard);
expect(blackboard.start).toEqual(2);
expect(blackboard.run).toEqual(4);
expect(blackboard.end).toEqual(2);
});
});
});