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