toEqual($expected) ->and($GLOBALS['rpn_error'])->toBeFalse(); })->with([ 'addition' => ['+', 8, 2, 10], 'subtraction' => ['-', 8, 2, 6], 'multiplication' => ['*', 8, 2, 16], 'division' => ['/', 8, 2, 4], 'modulo' => ['%', 8, 3, 2], // ^ is bitwise XOR (matching the pre-hardening eval('... ^ ...')), not // exponentiation: existing user thresholds rely on that semantic. 'bitwise xor' => ['^', 5, 3, 6], ]); test('unknown binary operators fail closed', function() { expect(thold_rpn_math_binary('**', 2, 3))->toBe(0) ->and($GLOBALS['rpn_error'])->toBeTrue() ->and(CactiStubs::$log)->not->toBeEmpty(); }); test('the expression evaluator routes binary math through the dispatcher', function() { $stack = [8, 2]; thold_expression_math_rpn('-', $stack); expect($stack)->toBe([6]) ->and($GLOBALS['rpn_error'])->toBeFalse(); });