ConstExprEvaluatorTest.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php declare(strict_types=1);
  2. namespace PhpParser;
  3. use PhpParser\Node\Expr;
  4. use PhpParser\Node\Scalar;
  5. class ConstExprEvaluatorTest extends \PHPUnit\Framework\TestCase
  6. {
  7. /** @dataProvider provideTestEvaluate */
  8. public function testEvaluate($exprString, $expected) {
  9. $parser = new Parser\Php7(new Lexer());
  10. $expr = $parser->parse('<?php ' . $exprString . ';')[0]->expr;
  11. $evaluator = new ConstExprEvaluator();
  12. $this->assertSame($expected, $evaluator->evaluateDirectly($expr));
  13. }
  14. public function provideTestEvaluate() {
  15. return [
  16. ['1', 1],
  17. ['1.0', 1.0],
  18. ['"foo"', "foo"],
  19. ['[0, 1]', [0, 1]],
  20. ['["foo" => "bar"]', ["foo" => "bar"]],
  21. ['NULL', null],
  22. ['False', false],
  23. ['true', true],
  24. ['+1', 1],
  25. ['-1', -1],
  26. ['~0', -1],
  27. ['!true', false],
  28. ['[0][0]', 0],
  29. ['"a"[0]', "a"],
  30. ['true ? 1 : (1/0)', 1],
  31. ['false ? (1/0) : 1', 1],
  32. ['42 ?: (1/0)', 42],
  33. ['false ?: 42', 42],
  34. ['false ?? 42', false],
  35. ['null ?? 42', 42],
  36. ['[0][0] ?? 42', 0],
  37. ['[][0] ?? 42', 42],
  38. ['0b11 & 0b10', 0b10],
  39. ['0b11 | 0b10', 0b11],
  40. ['0b11 ^ 0b10', 0b01],
  41. ['1 << 2', 4],
  42. ['4 >> 2', 1],
  43. ['"a" . "b"', "ab"],
  44. ['4 + 2', 6],
  45. ['4 - 2', 2],
  46. ['4 * 2', 8],
  47. ['4 / 2', 2],
  48. ['4 % 2', 0],
  49. ['4 ** 2', 16],
  50. ['1 == 1.0', true],
  51. ['1 != 1.0', false],
  52. ['1 < 2.0', true],
  53. ['1 <= 2.0', true],
  54. ['1 > 2.0', false],
  55. ['1 >= 2.0', false],
  56. ['1 <=> 2.0', -1],
  57. ['1 === 1.0', false],
  58. ['1 !== 1.0', true],
  59. ['true && true', true],
  60. ['true and true', true],
  61. ['false && (1/0)', false],
  62. ['false and (1/0)', false],
  63. ['false || false', false],
  64. ['false or false', false],
  65. ['true || (1/0)', true],
  66. ['true or (1/0)', true],
  67. ['true xor false', true],
  68. ];
  69. }
  70. public function testEvaluateFails() {
  71. $this->expectException(ConstExprEvaluationException::class);
  72. $this->expectExceptionMessage('Expression of type Expr_Variable cannot be evaluated');
  73. $evaluator = new ConstExprEvaluator();
  74. $evaluator->evaluateDirectly(new Expr\Variable('a'));
  75. }
  76. public function testEvaluateFallback() {
  77. $evaluator = new ConstExprEvaluator(function(Expr $expr) {
  78. if ($expr instanceof Scalar\MagicConst\Line) {
  79. return 42;
  80. }
  81. throw new ConstExprEvaluationException();
  82. });
  83. $expr = new Expr\BinaryOp\Plus(
  84. new Scalar\LNumber(8),
  85. new Scalar\MagicConst\Line()
  86. );
  87. $this->assertSame(50, $evaluator->evaluateDirectly($expr));
  88. }
  89. /**
  90. * @dataProvider provideTestEvaluateSilently
  91. */
  92. public function testEvaluateSilently($expr, $exception, $msg) {
  93. $evaluator = new ConstExprEvaluator();
  94. try {
  95. $evaluator->evaluateSilently($expr);
  96. } catch (ConstExprEvaluationException $e) {
  97. $this->assertSame(
  98. 'An error occurred during constant expression evaluation',
  99. $e->getMessage()
  100. );
  101. $prev = $e->getPrevious();
  102. $this->assertInstanceOf($exception, $prev);
  103. $this->assertSame($msg, $prev->getMessage());
  104. }
  105. }
  106. public function provideTestEvaluateSilently() {
  107. return [
  108. [
  109. new Expr\BinaryOp\Mod(new Scalar\LNumber(42), new Scalar\LNumber(0)),
  110. \Error::class,
  111. 'Modulo by zero'
  112. ],
  113. [
  114. new Expr\BinaryOp\Div(new Scalar\LNumber(42), new Scalar\LNumber(0)),
  115. \ErrorException::class,
  116. 'Division by zero'
  117. ],
  118. ];
  119. }
  120. }