UNPKG

behaviortree

Version:

A JavaScript implementation of Behavior Trees. They are useful for implementing AIs. For Browsers and NodeJS.

254 lines (253 loc) 11.4 kB
"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 */ const constants_1 = require("./constants"); const Sequence_1 = __importDefault(require("./Sequence")); const Task_1 = __importDefault(require("./Task")); describe('Sequence', () => { 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('stops immediately at a failing node', () => { const selector = new Sequence_1.default({ nodes: [failTask, successTask] }); selector.run(); expect(countSuccess).toEqual(0); expect(countFail).toEqual(1); }); it('stops at a failing node', () => { const selector = new Sequence_1.default({ nodes: [successTask, successTask, failTask, failTask, successTask] }); selector.run(); expect(countSuccess).toEqual(2); expect(countFail).toEqual(1); }); it('calls all tasks if all are successful', () => { const selector = new Sequence_1.default({ nodes: [successTask, successTask, successTask, successTask] }); selector.run(); expect(countSuccess).toEqual(4); expect(countFail).toEqual(0); }); it('does not call tasks after running task', () => { const selector = new Sequence_1.default({ nodes: [successTask, successTask, runningTask, successTask] }); selector.run(); expect(countSuccess).toEqual(2); expect(countRunning).toEqual(1); }); describe('result values', () => { it('returns SUCCESS if all task succeeds', () => { const selector = new Sequence_1.default({ nodes: [successTask, successTask, successTask] }); expect(selector.run()).toEqual(constants_1.SUCCESS); }); it('returns FAILURE if one task fails', () => { const selector = new Sequence_1.default({ nodes: [successTask, failTask, successTask, successTask] }); expect(selector.run()).toEqual(constants_1.FAILURE); }); it('returns the index of still running task as array of running lastRun', () => { const selector = new Sequence_1.default({ nodes: [successTask, successTask, runningTask, successTask] }); expect(selector.run()).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, constants_1.RUNNING] }); }); }); describe('blackboard', () => { const aTask = new Task_1.default({ run: function (blackboard) { ++blackboard.counter; return constants_1.SUCCESS; } }); const bTask = new Task_1.default({ run: function (blackboard) { blackboard.counter += 10; return constants_1.SUCCESS; } }); it('can be passed to a task, and stores data between different tasks', () => { const selector = new Sequence_1.default({ nodes: [aTask, bTask] }); const blackboard = { counter: 0 }; selector.run(blackboard); expect(blackboard.counter).toEqual(11); }); }); describe('nested selectors', () => { const aTask = new Task_1.default({ run: function (blackboard) { ++blackboard.aCounter; return constants_1.SUCCESS; } }); const bTask = new Task_1.default({ run: function (blackboard) { ++blackboard.bCounter; return constants_1.SUCCESS; } }); it('calls all nested tasks if all are succeeding', () => { const selector = new Sequence_1.default({ nodes: [ aTask, aTask, new Sequence_1.default({ nodes: [bTask, bTask, bTask] }) ] }); const blackboard = { aCounter: 0, bCounter: 0 }; selector.run(blackboard); expect(blackboard.aCounter).toEqual(2); expect(blackboard.bCounter).toEqual(3); }); describe('running tasks', () => { const switchTask = new Task_1.default({ run: function (blackboard) { ++blackboard.switchCounter; return blackboard.switchResult; } }); const selector = new Sequence_1.default({ nodes: [ aTask, aTask, new Sequence_1.default({ nodes: [bTask, switchTask, bTask] }), aTask ] }); it('returns lastRun if tasks are running', () => { const blackboard = { aCounter: 0, bCounter: 0, switchCounter: 0, switchResult: constants_1.RUNNING }; const result = selector.run(blackboard); expect(blackboard.aCounter).toEqual(2); expect(blackboard.bCounter).toEqual(1); expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, { total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.RUNNING] }] }); }); it('resumes tasks where we left off', () => { const blackboard = { aCounter: 0, bCounter: 0, switchCounter: 0, switchResult: constants_1.RUNNING }; let result = selector.run(blackboard); expect(blackboard.switchCounter).toEqual(1); expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, { total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.RUNNING] }] }); result = selector.run(blackboard, { lastRun: result }); expect(blackboard.switchCounter).toEqual(2); expect(blackboard.aCounter).toEqual(2); expect(blackboard.bCounter).toEqual(1); expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, { total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.RUNNING] }] }); }); it('after resuming in can progress, if tasks allow', () => { const blackboard = { aCounter: 0, bCounter: 0, switchCounter: 0, switchResult: constants_1.RUNNING }; let result = selector.run(blackboard); expect(blackboard.switchCounter).toEqual(1); expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, { total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.RUNNING] }] }); blackboard.switchResult = constants_1.SUCCESS; result = selector.run(blackboard, { lastRun: result }); expect(blackboard.switchCounter).toEqual(2); expect(blackboard.aCounter).toEqual(3); expect(blackboard.bCounter).toEqual(2); expect(result).toEqual(constants_1.SUCCESS); // expect(result).toEqual({ // total: SUCCESS, // state: [SUCCESS, SUCCESS, { total: SUCCESS, state: [SUCCESS, SUCCESS, SUCCESS] }, SUCCESS] // }); }); it('after resuming in can progress, if tasks allow it', () => { const blackboard = { aCounter: 0, bCounter: 0, switchCounter: 0, switchResult: constants_1.RUNNING }; let result = selector.run(blackboard); expect(blackboard.switchCounter).toEqual(1); expect(result).toEqual({ total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.SUCCESS, { total: constants_1.RUNNING, state: [constants_1.SUCCESS, constants_1.RUNNING] }] }); blackboard.switchResult = constants_1.FAILURE; result = selector.run(blackboard, { lastRun: result }); expect(blackboard.switchCounter).toEqual(2); // No count increments because of success expect(blackboard.aCounter).toEqual(2); expect(blackboard.bCounter).toEqual(1); expect(result).toEqual(constants_1.FAILURE); // expect(result).toEqual({ total: FAILURE, state: [SUCCESS, SUCCESS, { total: FAILURE, state: [SUCCESS, 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 selector = new Sequence_1.default({ nodes: [aTask, aTask, switchTask, aTask] }); const blackboard = { switchResult: constants_1.RUNNING, start: 0, run: 0, end: 0 }; const result = selector.run(blackboard); expect(blackboard.start).toEqual(1); expect(blackboard.run).toEqual(1); expect(blackboard.end).toEqual(0); const result2 = selector.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; selector.run(blackboard, { lastRun: result2, rerun: true }); expect(blackboard.start).toEqual(1); expect(blackboard.run).toEqual(3); expect(blackboard.end).toEqual(1); selector.run(blackboard); expect(blackboard.start).toEqual(2); expect(blackboard.run).toEqual(4); expect(blackboard.end).toEqual(2); }); }); }); });