UNPKG

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
"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); }); }); });