UNPKG

@yantra-core/sutra

Version:

A JavaScript behavior tree library for easily creating and managing complex behavior patterns in game development.

190 lines (145 loc) 7.42 kB
import tap from 'tape'; import Sutra from '../lib/sutra.js'; tap.test('Sutra Library Tests with GameState Context', async (parent) => { // Test for condition evaluation using both data and gameState parent.test('should evaluate conditions with data and gameState', async (t) => { const sutra = new Sutra(); // Custom function condition using both data and gameState sutra.addCondition('isDataAndGameStateValid', (data, gameState) => { return data.isValid && gameState.isGameRunning; }); // DSL condition (if applicable) using gameState // sutra.addCondition('isGameStateActive', { /* DSL condition that utilizes gameState */ }); // Test data and game state const testData = { isValid: true }; const testGameState = { isGameRunning: true }; t.equal(sutra.evaluateCondition('isDataAndGameStateValid', testData, testGameState), true, 'Condition with valid data and gameState should return true'); testGameState.isGameRunning = false; t.equal(sutra.evaluateCondition('isDataAndGameStateValid', testData, testGameState), false, 'Condition with invalid gameState should return false'); // Test composite conditions with gameState sutra.addCondition('compositeCondition', { op: 'and', conditions: ['isDataAndGameStateValid', 'someOtherCondition'] }); // Test conditions without gameState sutra.addCondition('isDataValid', data => data.isValid); t.equal(sutra.evaluateCondition('isDataValid', testData), true, 'Condition without gameState should still function correctly'); // Test with undefined or null gameState /* t.equal(sutra.evaluateCondition('isDataAndGameStateValid', testData, undefined), false, 'Condition should handle undefined gameState gracefully'); t.equal(sutra.evaluateCondition('isDataAndGameStateValid', testData, null), false, 'Condition should handle null gameState gracefully'); */ t.end(); }); }); tap.test('Sutra Integration Tests with GameState Context', async (parent) => { // Test for condition evaluation using both data and gameState parent.test('should evaluate conditions with data and gameState', async (t) => { const sutra = new Sutra(); // Adding a custom function condition that uses both data and gameState sutra.addCondition('isDataAndGameStateValid', (data, gameState) => { return data.isValid && gameState.isGameRunning; }); // Test data and game state const testData = { isValid: true }; const testGameState = { isGameRunning: true }; t.equal(sutra.evaluateCondition('isDataAndGameStateValid', testData, testGameState), true, 'isDataAndGameStateValid should return true when both data and gameState are valid'); // Change gameState and test again testGameState.isGameRunning = false; t.equal(sutra.evaluateCondition('isDataAndGameStateValid', testData, testGameState), false, 'isDataAndGameStateValid should return false when gameState is invalid'); t.end(); }); // Test for Sutra.tick() with gameState parent.test('Sutra.tick() should handle gameState', async (t) => { const sutra = new Sutra(); // Adding a condition and action sutra.addCondition('isGameActive', (data, gameState) => gameState.isActive); sutra.addAction({ if: 'isGameActive', then: [{ action: 'logAction' }] }); sutra.on('logAction', (data, node) => { t.pass('Action triggered when gameState is active'); }); const gameActiveState = { isActive: true }; sutra.tick({}, gameActiveState); // Simulate tick with active game state const gameInactiveState = { isActive: false }; sutra.tick({}, gameInactiveState); // Simulate tick with inactive game state t.end(); }); }); tap.test('Sutra Deeply Nested GameState Tests', async (parent) => { parent.test('should evaluate conditions with deeply nested gameState values', async (t) => { const sutra = new Sutra(); // Adding a condition to check a deeply nested value in gameState sutra.addCondition('nestedValueCheck', { op: 'lessThan', gamePropertyPath: 'level.stats.blockCount', value: 5 }); // Simulating a gameState with deeply nested properties const gameState = { level: { stats: { blockCount: 3 } } }; t.equal(sutra.evaluateCondition('nestedValueCheck', {}, gameState), true, 'nestedValueCheck should return true for blockCount < 5'); // Modifying the gameState to change the block count gameState.level.stats.blockCount = 6; t.equal(sutra.evaluateCondition('nestedValueCheck', {}, gameState), false, 'nestedValueCheck should return false for blockCount >= 5'); // Testing with different types of nested values sutra.addCondition('nestedStringCheck', { op: 'equals', gamePropertyPath: 'level.description', value: 'Level 1' }); gameState.level.description = 'Level 1'; t.equal(sutra.evaluateCondition('nestedStringCheck', {}, gameState), true, 'nestedStringCheck should return true for matching string'); gameState.level.description = 'Level 2'; t.equal(sutra.evaluateCondition('nestedStringCheck', {}, gameState), false, 'nestedStringCheck should return false for non-matching string'); // Testing with an array sutra.addCondition('nestedArrayLengthCheck', { op: 'greaterThanOrEqual', gamePropertyPath: 'level.enemies.length', value: 2 }); gameState.level.enemies = ['enemy1', 'enemy2']; t.equal(sutra.evaluateCondition('nestedArrayLengthCheck', {}, gameState), true, 'nestedArrayLengthCheck should return true for array length >= 2'); gameState.level.enemies = ['enemy1']; t.equal(sutra.evaluateCondition('nestedArrayLengthCheck', {}, gameState), false, 'nestedArrayLengthCheck should return false for array length < 2'); // Testing with an undefined array sutra.addCondition('nestedUndefinedArrayLengthCheck', { op: 'equals', gamePropertyPath: 'level.items.length', value: 0 }); // Simulating gameState where the array is undefined delete gameState.level.enemies; // or gameState.level.enemies = undefined; t.equal(sutra.evaluateCondition('nestedUndefinedArrayLengthCheck', {}, gameState), true, 'nestedUndefinedArrayLengthCheck should return true for undefined array length equaling 0'); t.end(); }); }); tap.test('Sutra GameState Array Item Test', async (parent) => { parent.test('should evaluate conditions based on specific items in an array within gameState', async (t) => { const sutra = new Sutra(); // Adding a condition to check a specific item in an array within gameState sutra.addCondition('arrayItemCheck', { op: 'equals', gamePropertyPath: 'level.powerUps[1]', value: 'speedBoost' }); // Simulating a gameState with an array containing specific items const gameState = { level: { powerUps: ['shield', 'speedBoost', 'extraLife'] } }; t.equal(sutra.evaluateCondition('arrayItemCheck', {}, gameState), true, 'arrayItemCheck should return true for specific array item matching'); // Changing the array item to a different value gameState.level.powerUps[1] = 'invisibility'; t.equal(sutra.evaluateCondition('arrayItemCheck', {}, gameState), false, 'arrayItemCheck should return false for non-matching array item'); t.end(); }); });