import { evaluateCondition, OPS } from '../src/engine/conditionEvaluator.js'; function assert(cond, msg) { if (!cond) throw new Error(msg); } // Test state matching the reference const state = { age: 15, reincarnation: 2, money: 300, stats: { body: 30, wisdom: 20, charm: 10, destiny: 5, business: 8, intelligence: 15 }, careers: { student: { level: 120 } }, identity: 'orphan', worldFlags: { met_taoist: true }, shopItems: { taoist_license: 1 }, artifacts: { immortal_sword: 3 } }; // Test OPS constant exists assert(typeof OPS === 'object', 'OPS should be an object'); assert(typeof OPS['>='] === 'function', 'OPS[">="] should be a function'); // === age conditions === assert(evaluateCondition({ type: 'age', op: '>=', value: 14 }, state) === true, 'age >= 14 should be true'); assert(evaluateCondition({ type: 'age', op: '>=', value: 16 }, state) === false, 'age >= 16 should be false'); assert(evaluateCondition({ type: 'age', op: '==', value: 15 }, state) === true, 'age == 15 should be true'); assert(evaluateCondition({ type: 'age', op: '>', value: 10 }, state) === true, 'age > 10 should be true'); assert(evaluateCondition({ type: 'age', op: '<', value: 20 }, state) === true, 'age < 20 should be true'); assert(evaluateCondition({ type: 'age', op: '<=', value: 15 }, state) === true, 'age <= 15 should be true'); assert(evaluateCondition({ type: 'age', op: '!=', value: 10 }, state) === true, 'age != 10 should be true'); // === stat conditions === assert(evaluateCondition({ type: 'stat', stat: 'body', op: '>=', value: 20 }, state) === true, 'stat body >= 20 should be true'); assert(evaluateCondition({ type: 'stat', stat: 'body', op: '>=', value: 40 }, state) === false, 'stat body >= 40 should be false'); assert(evaluateCondition({ type: 'stat', stat: 'wisdom', op: '==', value: 20 }, state) === true, 'stat wisdom == 20 should be true'); assert(evaluateCondition({ type: 'stat', stat: 'charm', op: '<', value: 20 }, state) === true, 'stat charm < 20 should be true'); assert(evaluateCondition({ type: 'stat', stat: 'destiny', op: '>', value: 0 }, state) === true, 'stat destiny > 0 should be true'); // Missing stat defaults to 0 assert(evaluateCondition({ type: 'stat', stat: 'nonexistent', op: '==', value: 0 }, state) === true, 'missing stat == 0 should be true'); // === careerLevel conditions === assert(evaluateCondition({ type: 'careerLevel', careerId: 'student', op: '>=', value: 100 }, state) === true, 'careerLevel student >= 100 should be true'); assert(evaluateCondition({ type: 'careerLevel', careerId: 'student', op: '>=', value: 200 }, state) === false, 'careerLevel student >= 200 should be false'); assert(evaluateCondition({ type: 'careerLevel', careerId: 'student', op: '==', value: 120 }, state) === true, 'careerLevel student == 120 should be true'); // Missing career defaults to 0 assert(evaluateCondition({ type: 'careerLevel', careerId: 'missing', op: '==', value: 0 }, state) === true, 'missing career level == 0 should be true'); // === money conditions === assert(evaluateCondition({ type: 'money', op: '>=', value: 200 }, state) === true, 'money >= 200 should be true'); assert(evaluateCondition({ type: 'money', op: '>=', value: 500 }, state) === false, 'money >= 500 should be false'); assert(evaluateCondition({ type: 'money', op: '==', value: 300 }, state) === true, 'money == 300 should be true'); assert(evaluateCondition({ type: 'money', op: '<', value: 500 }, state) === true, 'money < 500 should be true'); // === identity conditions === assert(evaluateCondition({ type: 'identity', value: 'orphan' }, state) === true, 'identity orphan should be true'); assert(evaluateCondition({ type: 'identity', value: 'noble' }, state) === false, 'identity noble should be false'); // === worldFlag conditions === assert(evaluateCondition({ type: 'worldFlag', flag: 'met_taoist', value: true }, state) === true, 'worldFlag met_taoist == true should be true'); assert(evaluateCondition({ type: 'worldFlag', flag: 'met_taoist' }, state) === true, 'worldFlag met_taoist (no value) should be true'); assert(evaluateCondition({ type: 'worldFlag', flag: 'met_king', value: true }, state) === false, 'worldFlag met_king == true should be false'); assert(evaluateCondition({ type: 'worldFlag', flag: 'met_king' }, state) === false, 'worldFlag met_king (no value) should be false'); // === hasItem conditions === assert(evaluateCondition({ type: 'hasItem', itemId: 'taoist_license' }, state) === true, 'hasItem taoist_license should be true'); assert(evaluateCondition({ type: 'hasItem', itemId: 'missing_item' }, state) === false, 'hasItem missing_item should be false'); // === hasArtifact conditions === assert(evaluateCondition({ type: 'hasArtifact', artifactId: 'immortal_sword' }, state) === true, 'hasArtifact immortal_sword should be true'); assert(evaluateCondition({ type: 'hasArtifact', artifactId: 'immortal_sword', op: '>=', value: 3 }, state) === true, 'hasArtifact immortal_sword >= 3 should be true'); assert(evaluateCondition({ type: 'hasArtifact', artifactId: 'immortal_sword', op: '>', value: 5 }, state) === false, 'hasArtifact immortal_sword > 5 should be false'); assert(evaluateCondition({ type: 'hasArtifact', artifactId: 'missing_artifact' }, state) === false, 'hasArtifact missing_artifact should be false'); assert(evaluateCondition({ type: 'hasArtifact', artifactId: 'missing_artifact', op: '==', value: 0 }, state) === true, 'hasArtifact missing_artifact == 0 should be true'); // === reincarnation conditions === assert(evaluateCondition({ type: 'reincarnation', op: '>=', value: 1 }, state) === true, 'reincarnation >= 1 should be true'); assert(evaluateCondition({ type: 'reincarnation', op: '>=', value: 5 }, state) === false, 'reincarnation >= 5 should be false'); assert(evaluateCondition({ type: 'reincarnation', op: '==', value: 2 }, state) === true, 'reincarnation == 2 should be true'); // === and conditions === assert(evaluateCondition({ type: 'and', conditions: [ { type: 'age', op: '>=', value: 14 }, { type: 'stat', stat: 'body', op: '>=', value: 20 } ] }, state) === true, 'and with two true conditions should be true'); assert(evaluateCondition({ type: 'and', conditions: [ { type: 'age', op: '>=', value: 14 }, { type: 'stat', stat: 'body', op: '>=', value: 50 } ] }, state) === false, 'and with one false condition should be false'); assert(evaluateCondition({ type: 'and', conditions: [] }, state) === true, 'and with empty conditions should be true (vacuous truth)'); // === or conditions === assert(evaluateCondition({ type: 'or', conditions: [ { type: 'age', op: '>=', value: 20 }, { type: 'stat', stat: 'body', op: '>=', value: 20 } ] }, state) === true, 'or with one true condition should be true'); assert(evaluateCondition({ type: 'or', conditions: [ { type: 'age', op: '>=', value: 20 }, { type: 'stat', stat: 'body', op: '>=', value: 50 } ] }, state) === false, 'or with all false conditions should be false'); assert(evaluateCondition({ type: 'or', conditions: [] }, state) === false, 'or with empty conditions should be false'); // === not conditions === assert(evaluateCondition({ type: 'not', condition: { type: 'age', op: '>=', value: 20 } }, state) === true, 'not of false condition should be true'); assert(evaluateCondition({ type: 'not', condition: { type: 'age', op: '>=', value: 14 } }, state) === false, 'not of true condition should be false'); // === nested compound conditions === assert(evaluateCondition({ type: 'and', conditions: [ { type: 'or', conditions: [ { type: 'age', op: '>=', value: 20 }, { type: 'identity', value: 'orphan' } ]}, { type: 'not', condition: { type: 'stat', stat: 'body', op: '<', value: 10 }} ] }, state) === true, 'nested compound condition should be true'); // === invalid/edge cases === assert(evaluateCondition(null, state) === false, 'null condition should be false'); assert(evaluateCondition({}, state) === false, 'empty object should be false'); assert(evaluateCondition({ type: 'unknown' }, state) === false, 'unknown type should be false'); assert(evaluateCondition({ type: 'age', op: 'invalid', value: 10 }, state) === false, 'invalid operator should be false'); console.log('All conditionEvaluator tests PASS');