Chris@13: parse('expr; Chris@13: $evaluator = new ConstExprEvaluator(); Chris@13: $this->assertSame($expected, $evaluator->evaluateDirectly($expr)); Chris@13: } Chris@13: Chris@13: public function provideTestEvaluate() { Chris@13: return [ Chris@13: ['1', 1], Chris@13: ['1.0', 1.0], Chris@13: ['"foo"', "foo"], Chris@13: ['[0, 1]', [0, 1]], Chris@13: ['["foo" => "bar"]', ["foo" => "bar"]], Chris@13: ['NULL', null], Chris@13: ['False', false], Chris@13: ['true', true], Chris@13: ['+1', 1], Chris@13: ['-1', -1], Chris@13: ['~0', -1], Chris@13: ['!true', false], Chris@13: ['[0][0]', 0], Chris@13: ['"a"[0]', "a"], Chris@13: ['true ? 1 : (1/0)', 1], Chris@13: ['false ? (1/0) : 1', 1], Chris@13: ['42 ?: (1/0)', 42], Chris@13: ['false ?: 42', 42], Chris@13: ['false ?? 42', false], Chris@13: ['null ?? 42', 42], Chris@13: ['[0][0] ?? 42', 0], Chris@13: ['[][0] ?? 42', 42], Chris@13: ['0b11 & 0b10', 0b10], Chris@13: ['0b11 | 0b10', 0b11], Chris@13: ['0b11 ^ 0b10', 0b01], Chris@13: ['1 << 2', 4], Chris@13: ['4 >> 2', 1], Chris@13: ['"a" . "b"', "ab"], Chris@13: ['4 + 2', 6], Chris@13: ['4 - 2', 2], Chris@13: ['4 * 2', 8], Chris@13: ['4 / 2', 2], Chris@13: ['4 % 2', 0], Chris@13: ['4 ** 2', 16], Chris@13: ['1 == 1.0', true], Chris@13: ['1 != 1.0', false], Chris@13: ['1 < 2.0', true], Chris@13: ['1 <= 2.0', true], Chris@13: ['1 > 2.0', false], Chris@13: ['1 >= 2.0', false], Chris@13: ['1 <=> 2.0', -1], Chris@13: ['1 === 1.0', false], Chris@13: ['1 !== 1.0', true], Chris@13: ['true && true', true], Chris@13: ['true and true', true], Chris@13: ['false && (1/0)', false], Chris@13: ['false and (1/0)', false], Chris@13: ['false || false', false], Chris@13: ['false or false', false], Chris@13: ['true || (1/0)', true], Chris@13: ['true or (1/0)', true], Chris@13: ['true xor false', true], Chris@13: ]; Chris@13: } Chris@13: Chris@13: public function testEvaluateFails() { Chris@17: $this->expectException(ConstExprEvaluationException::class); Chris@17: $this->expectExceptionMessage('Expression of type Expr_Variable cannot be evaluated'); Chris@13: $evaluator = new ConstExprEvaluator(); Chris@13: $evaluator->evaluateDirectly(new Expr\Variable('a')); Chris@13: } Chris@13: Chris@13: public function testEvaluateFallback() { Chris@13: $evaluator = new ConstExprEvaluator(function(Expr $expr) { Chris@13: if ($expr instanceof Scalar\MagicConst\Line) { Chris@13: return 42; Chris@13: } Chris@13: throw new ConstExprEvaluationException(); Chris@13: }); Chris@13: $expr = new Expr\BinaryOp\Plus( Chris@13: new Scalar\LNumber(8), Chris@13: new Scalar\MagicConst\Line() Chris@13: ); Chris@13: $this->assertSame(50, $evaluator->evaluateDirectly($expr)); Chris@13: } Chris@13: Chris@13: /** Chris@13: * @dataProvider provideTestEvaluateSilently Chris@13: */ Chris@13: public function testEvaluateSilently($expr, $exception, $msg) { Chris@13: $evaluator = new ConstExprEvaluator(); Chris@13: Chris@13: try { Chris@13: $evaluator->evaluateSilently($expr); Chris@13: } catch (ConstExprEvaluationException $e) { Chris@13: $this->assertSame( Chris@13: 'An error occurred during constant expression evaluation', Chris@13: $e->getMessage() Chris@13: ); Chris@13: Chris@13: $prev = $e->getPrevious(); Chris@13: $this->assertInstanceOf($exception, $prev); Chris@13: $this->assertSame($msg, $prev->getMessage()); Chris@13: } Chris@13: } Chris@13: Chris@13: public function provideTestEvaluateSilently() { Chris@13: return [ Chris@13: [ Chris@13: new Expr\BinaryOp\Mod(new Scalar\LNumber(42), new Scalar\LNumber(0)), Chris@13: \Error::class, Chris@13: 'Modulo by zero' Chris@13: ], Chris@13: [ Chris@13: new Expr\BinaryOp\Div(new Scalar\LNumber(42), new Scalar\LNumber(0)), Chris@13: \ErrorException::class, Chris@13: 'Division by zero' Chris@13: ], Chris@13: ]; Chris@13: } Chris@13: }