From 3a46a8e7992ea60eb1d0de02193569a958f4b69c Mon Sep 17 00:00:00 2001 From: florianv Date: Thu, 27 Feb 2014 03:45:51 +0100 Subject: [PATCH] Fixed evaluation of short circuit operators --- .../ExpressionLanguage/Node/BinaryNode.php | 12 +++-- .../Tests/ExpressionLanguageTest.php | 44 ++++++++++++++++++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php b/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php index 15341e86c5..0082254b45 100644 --- a/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php +++ b/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php @@ -83,9 +83,10 @@ class BinaryNode extends Node { $operator = $this->attributes['operator']; $left = $this->nodes['left']->evaluate($functions, $values); - $right = $this->nodes['right']->evaluate($functions, $values); if (isset(self::$functions[$operator])) { + $right = $this->nodes['right']->evaluate($functions, $values); + if ('not in' == $operator) { return !call_user_func('in_array', $left, $right); } @@ -96,10 +97,15 @@ class BinaryNode extends Node switch ($operator) { case 'or': case '||': - return $left || $right; + return $left || $this->nodes['right']->evaluate($functions, $values); case 'and': case '&&': - return $left && $right; + return $left && $this->nodes['right']->evaluate($functions, $values); + } + + $right = $this->nodes['right']->evaluate($functions, $values); + + switch ($operator) { case '|': return $left | $right; case '^': diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php index c8481af23c..65d2fcb8a8 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\ExpressionLanguage\Tests; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; -use Symfony\Component\ExpressionLanguage\ParsedExpression; class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase { @@ -54,4 +53,47 @@ class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase $expressionLanguage = new ExpressionLanguage(); $this->assertEquals('constant("PHP_VERSION")', $expressionLanguage->compile('constant("PHP_VERSION")')); } + + /** + * @dataProvider shortCircuitProviderEvaluate + */ + public function testShortCircuitOperatorsEvaluate($expression, array $values, $expected) + { + $expressionLanguage = new ExpressionLanguage(); + $this->assertEquals($expected, $expressionLanguage->evaluate($expression, $values)); + } + + /** + * @dataProvider shortCircuitProviderCompile + */ + public function testShortCircuitOperatorsCompile($expression, array $names, $expected) + { + $result = null; + $expressionLanguage = new ExpressionLanguage(); + eval(sprintf('$result = %s;', $expressionLanguage->compile($expression, $names))); + $this->assertSame($expected, $result); + } + + public function shortCircuitProviderEvaluate() + { + $object = $this->getMockBuilder('stdClass')->setMethods(array('foo'))->getMock(); + $object->expects($this->never())->method('foo'); + + return array( + array('false and object.foo()', array('object' => $object), false), + array('false && object.foo()', array('object' => $object), false), + array('true || object.foo()', array('object' => $object), true), + array('true or object.foo()', array('object' => $object), true), + ); + } + + public function shortCircuitProviderCompile() + { + return array( + array('false and foo', array('foo' => 'foo'), false), + array('false && foo', array('foo' => 'foo'), false), + array('true || foo', array('foo' => 'foo'), true), + array('true or foo', array('foo' => 'foo'), true), + ); + } }