添加更多單元測試

pull/1/head
韩天峰 8 months ago
parent c1d759de57
commit 4f095c301d
  1. 23
      examples/array.php
  2. 10
      examples/ns.cc
  3. 6
      examples/object_cast.php
  4. 76
      src/Php/Translator.php
  5. 28
      tests/zend/add_002.phpt
  6. 28
      tests/zend/add_003.phpt
  7. 23
      tests/zend/add_004.phpt
  8. 56
      tests/zend/add_006.phpt
  9. 27
      tests/zend/add_007.phpt
  10. 18
      tests/zend/assign_dim_op_same_var.phpt
  11. 21
      tests/zend/assign_dim_op_undef.phpt
  12. 16
      tests/zend/break_error_001.phpt
  13. 12
      tests/zend/break_error_002.phpt
  14. 12
      tests/zend/break_error_003.phpt
  15. 17
      tests/zend/break_error_004.phpt
  16. 38
      tests/zend/exceptions/exception_001.phpt
  17. 21
      tests/zend/exceptions/exception_002.phpt
  18. 13
      tests/zend/exceptions/exception_003.phpt
  19. 15
      tests/zend/exceptions/exception_006.phpt
  20. 35
      tests/zend/exceptions/exception_007.phpt
  21. 17
      tests/zend/exceptions/exception_011.phpt
  22. 20
      tests/zend/exceptions/exception_015.phpt
  23. 14
      tests/zend/exceptions/exception_019.phpt
  24. 14
      tests/zend/exceptions/exception_022.phpt
  25. 19
      tests/zend/xor_001.phpt
  26. 39
      tests/zend/xor_002.phpt
  27. 19
      tests/zend/xor_003.phpt
  28. 12
      tests/zend/zend_operators.phpt

@ -0,0 +1,23 @@
<?php
function safe_write($fd, $data)
{
$len = strlen($data);
do {
$w = fwrite($fd, $data);
$len -= $w;
} while ($len && ($data = substr($data, $w)) !== FALSE);
}
function sync($tmp)
{
global $pipe;
$data = "hello world";
safe_write($pipe, $data);
}
function main()
{
global $pipe;
$pipes = stream_socket_pair(AF_UNIX, SOCK_STREAM, 0);
$pipe = $pipes[0];
}

@ -0,0 +1,10 @@
#include <phpx.h>
#include <phpx_func.h>
#include <php_func_decl.h>
using namespace php;
Int php_test(Int a, Var b, Str c, Array d) {
php_var_dump(d, 10);
return 0;
}

@ -0,0 +1,6 @@
<?php
function main()
{
$obj = (object)'ciao';
echo $obj->scalar; // 输出 'ciao'
}

@ -29,6 +29,7 @@ class Translator extends \PhpAot\Core\Translator
const string VALUE_INF = 'std::numeric_limits<double>::infinity()';
const string LITERAL_STRINGS = '_literal_strings';
const string EXPR_VARIABLE = 'Expr_Variable';
const string EXPR_NEW = 'Expr_New';
const string EXPR_ARRAY_DIM_FETCH = 'Expr_ArrayDimFetch';
private string $phpxDir = '~/workspace/projects/phpx';
@ -130,6 +131,8 @@ class Translator extends \PhpAot\Core\Translator
private CLImate $climate;
private array $beforeStmtLines = [];
private array $afterStmtLines = [];
private bool $inLoop = false;
private bool $inSwitch = false;
public function __construct(string $rootPath)
{
@ -507,19 +510,29 @@ class Translator extends \PhpAot\Core\Translator
$result = $this->parseReturn($v) . ';';
break;
case 'Stmt_For':
$this->inLoop = true;
$result = $this->parseFor($v);
$this->inLoop = false;
break;
case 'Stmt_Foreach':
$this->inLoop = true;
$result = $this->parseForeach($v);
$this->inLoop = false;
break;
case 'Stmt_Switch':
$this->inSwitch = true;
$result = $this->parseSwitch($v);
$this->inSwitch = false;
break;
case 'Stmt_While':
$this->inLoop = true;
$result = $this->parseWhile($v);
$this->inLoop = false;
break;
case 'Stmt_Do':
$this->inLoop = true;
$result = $this->parseDo($v);
$this->inLoop = false;
break;
case 'Stmt_If':
$result = $this->parseIf($v);
@ -527,6 +540,12 @@ class Translator extends \PhpAot\Core\Translator
case 'Stmt_Break':
$result = $this->parseBreak($v);
break;
case 'Stmt_Goto':
$result = $this->parseGoto($v);
break;
case 'Stmt_Label':
$result = $this->parseLabel($v);
break;
case 'Stmt_Continue':
$result = 'continue;';
break;
@ -624,6 +643,8 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseAssignOpShiftRight($expr);
case 'Expr_AssignOp_BitwiseAnd':
return $this->parseAssignOpBitwiseAnd($expr);
case 'Expr_AssignOp_BitwiseXor':
return $this->parseAssignOpBitwiseXor($expr);
case 'Expr_AssignOp_Pow':
return $this->parseAssignOpPow($expr);
case 'Expr_BinaryOp_Mul':
@ -681,6 +702,8 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseNew($expr);
case 'Expr_Clone':
return $this->parseClone($expr);
case 'Expr_Instanceof':
return $this->parseInstanceof($expr);
case 'Expr_Throw':
return $this->parseThrow($expr);
case 'Expr_ShellExec':
@ -710,6 +733,8 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseCastString($expr);
case 'Expr_Cast_Array':
return $this->parseCastArray($expr);
case 'Expr_Cast_Object':
return $this->parseCastObject($expr);
case 'Expr_ConstFetch':
return $this->parseConstFetch($expr);
case 'Expr_UnaryMinus':
@ -747,7 +772,7 @@ class Translator extends \PhpAot\Core\Translator
}
} elseif ($left->getType() === 'Expr_PropertyFetch') {
$array = $this->parseIdentifier($left->var);
$propName = $this->parseIdentifier($left->name);
$propName = $this->identifierToStr($left->name);
return "$array.setProperty($propName, " . $this->trimBrackets($this->parseExpr($right)) . ")";
} elseif ($right->getType() === 'Expr_Assign') {
$chain[] = $left;
@ -1620,6 +1645,14 @@ class Translator extends \PhpAot\Core\Translator
return $expr;
}
private function convertObjectExpr(string $expr): string
{
if (!$this->isClosedCall($expr, 'php::to_object')) {
return 'php::to_object(' . $this->trimBrackets($expr) . ')';
}
return $expr;
}
private function convertArrayExpr(string $expr): string
{
if (!$this->isClosedCall($expr, 'php::to_array')) {
@ -1706,6 +1739,12 @@ class Translator extends \PhpAot\Core\Translator
return $var . '.clone()';
}
private function parseInstanceof(Node $expr): string
{
$var = $this->parseIdentifier($expr->expr);
return $var . '.instanceOf(' . $this->identifierToStr($expr->class) . ')';
}
private function parseNamespaceDef(Node $node): string
{
$this->namespace = $this->parseIdentifier($node->name);
@ -1769,6 +1808,11 @@ class Translator extends \PhpAot\Core\Translator
return $this->convertBoolExpr($this->parseExpr($node->expr));
}
private function parseCastObject(mixed $node): string
{
return $this->convertObjectExpr($this->parseExpr($node->expr));
}
private function parseConstFetch(Node $expr): string
{
$name = $this->parseIdentifier($expr->name);
@ -1922,6 +1966,12 @@ class Translator extends \PhpAot\Core\Translator
return $var . ' >>= ' . $this->parseIdentifier($node->expr);
}
private function parseAssignOpBitwiseXor(Node $node): string
{
$var = $this->parseIdentifier($node->var);
return $var . ' ^= ' . $this->parseIdentifier($node->expr);
}
private function parseMagicConstFile(mixed $expr): string
{
return '"' . $this->escapeString($this->file) . '"';
@ -1952,7 +2002,7 @@ class Translator extends \PhpAot\Core\Translator
if ($this->hasGlobalVar($keyVar)) {
$this->fatalError($node->keyVar, 'Cannot redefine key variable: ' . $this->unescapeVarName($keyVar));
}
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $keyVar . ' = iter.key();' . PHP_EOL;
$code .= $this->getIndent() . ' ' . $keyVar . ' = iter.key();' . PHP_EOL;
if (!$this->hasVar($keyVar)) {
$this->addLocalVar($keyVar, self::TYPE_VAR);
}
@ -1970,7 +2020,7 @@ class Translator extends \PhpAot\Core\Translator
if ($this->hasGlobalVar($valueVar)) {
$this->fatalError($node->valueVar, 'Cannot redefine value variable: ' . $this->unescapeVarName($valueVar));
}
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = iter.value();' . PHP_EOL;
$code .= $this->getIndent() . ' ' . $valueVar . ' = iter.value();' . PHP_EOL;
if (!$this->hasVar($valueVar)) {
$this->addLocalVar($valueVar, self::TYPE_VAR);
}
@ -2095,11 +2145,14 @@ class Translator extends \PhpAot\Core\Translator
private function parseBreak(mixed $v): string
{
if (!$this->inLoop and !$this->inSwitch) {
$this->fatalError($v, 'Cannot break outside loop');
}
$num = $v->num;
if ($num) {
$value = $this->parseIdentifier($num);
if ($value > 1) {
abort($v);
$this->fatalError($v, 'Cannot break more than 1 level');
}
}
return 'break;';
@ -2327,6 +2380,9 @@ class Translator extends \PhpAot\Core\Translator
private function parseThrow(mixed $expr): string
{
if ($expr->expr->getType() != self::EXPR_VARIABLE and $expr->expr->getType() != self::EXPR_NEW) {
$this->fatalError($expr, 'The throw statement only accepts a object variable');
}
return 'php::throwException(' . $this->parseIdentifier($expr->expr). ')';
}
@ -2393,4 +2449,16 @@ class Translator extends \PhpAot\Core\Translator
{
return 'php::call("shell_exec", {' . $this->parseInterpolatedString($expr) . '})';
}
private function parseGoto(Node $v): string
{
$this->fatalError($v, 'Goto statement is not supported');
return 'goto ' . $v->name->name . ';';
}
private function parseLabel(Node $v): string
{
$this->fatalError($v, 'Label statement is not supported');
return $v->name->name . ':';
}
}

@ -0,0 +1,28 @@
--TEST--
adding objects to arrays
--FILE--
<?php
$a = array(1,2,3);
$o = new stdclass;
$o->prop = "value";
try {
var_dump($a + $o);
} catch (Error $e) {
echo "\nException: " . $e->getMessage() . "\n";
}
$c = $a + $o;
var_dump($c);
echo "Done\n";
?>
--EXPECTF--
Exception: Unsupported operand types: array + stdClass
Fatal error: Uncaught TypeError: Unsupported operand types: array + stdClass in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

@ -0,0 +1,28 @@
--TEST--
adding arrays to objects
--FILE--
<?php
$a = array(1,2,3);
$o = new stdclass;
$o->prop = "value";
try {
var_dump($o + $a);
} catch (Error $e) {
echo "\nException: " . $e->getMessage() . "\n";
}
$c = $o + $a;
var_dump($c);
echo "Done\n";
?>
--EXPECTF--
Exception: Unsupported operand types: stdClass + array
Fatal error: Uncaught TypeError: Unsupported operand types: stdClass + array in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

@ -0,0 +1,23 @@
--TEST--
adding numbers to arrays
--FILE--
<?php
$a = array(1,2,3);
try {
var_dump($a + 5);
} catch (Error $e) {
echo "\nException: " . $e->getMessage() . "\n";
}
$c = $a + 5;
var_dump($c);
echo "Done\n";
?>
--EXPECTF--
int(6)
int(6)
Done

@ -0,0 +1,56 @@
--TEST--
adding numbers to strings
--INI--
precision=14
--FILE--
<?php
$i = 75636;
$s1 = "this is a string";
$s2 = "876222numeric";
$s3 = "48474874";
$s4 = "25.68";
try {
$c = $i + $s1;
var_dump($c);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}
$c = $i + $s2;
var_dump($c);
$c = $i + $s3;
var_dump($c);
$c_float = $i + floatval($s4);
var_dump($c_float);
try {
$c = $s1 + $i;
var_dump($c);
} catch (\TypeError $e) {
echo $e->getMessage() . \PHP_EOL;
}
$c = $s2 + $i;
var_dump($c);
$c = $s3 + $i;
var_dump($c);
$c_float3 = floatval($s4) + $i;
var_dump($c_float3);
echo "Done\n";
?>
--EXPECTF--
int(75636)
int(951858)
int(48550510)
float(75661.68)
int(75636)
int(951858)
int(48550510)
float(75661.68)
Done

@ -0,0 +1,27 @@
--TEST--
adding strings to arrays
--FILE--
<?php
$a = array(1,2,3);
$s1 = "some string";
try {
var_dump($a + $s1);
} catch (Error $e) {
echo "\nException: " . $e->getMessage() . "\n";
}
$c = $a + $s1;
var_dump($c);
echo "Done\n";
?>
--EXPECTF--
Exception: Unsupported operand types: array + string
Fatal error: Uncaught TypeError: Unsupported operand types: array + string in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

@ -0,0 +1,18 @@
--TEST--
Compound array assignment with same variable
--FILE--
<?php
function main() {
$ary = [[]];
$ary[0] += $ary;
foreach ($ary as $v) {
var_dump($v);
}
}
?>
--EXPECT--
array(1) {
[0]=>
array(0) {
}
}

@ -0,0 +1,21 @@
--TEST--
Compound array assign with undefined variables
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
$a[$b] += 1;
var_dump($a);
?>
--EXPECTF--
Warning: Undefined variable $a in %s on line %d
Warning: Undefined variable $b in %s on line %d
Deprecated: Using null as an array offset is deprecated, use an empty string instead in %s on line %d
Warning: Undefined array key "" in %s on line %d
array(1) {
[""]=>
int(1)
}

@ -0,0 +1,16 @@
--TEST--
'break' error (non positive integers)
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
function foo () {
break 0;
}
function main() {
foo();
}
?>
--EXPECTF--
Fatal error: 'break' operator accepts only positive integers in %sbreak_error_001.php on line 3

@ -0,0 +1,12 @@
--TEST--
'break' error (operator with non-integer operand)
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
function foo () {
break $x;
}
?>
--EXPECTF--
Fatal error: 'break' operator with non-integer operand is no longer supported in %sbreak_error_002.php on line 3

@ -0,0 +1,12 @@
--TEST--
'break' error (not in the loop context)
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
function foo () {
break;
}
?>
--EXPECTF--
Fatal error: 'break' not in the 'loop' or 'switch' context in %sbreak_error_003.php on line 3

@ -0,0 +1,17 @@
--TEST--
'break' error (wrong level)
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
function foo () {
while (1) {
break 2;
}
}
function main() {
foo();
}
?>
--EXPECTF--
Fatal error: Cannot 'break' 2 levels in %sbreak_error_004.php on line 4

@ -0,0 +1,38 @@
--TEST--
Testing nested exceptions
--FILE--
<?php
try {
try {
try {
try {
throw new Exception();
} catch (Exception $e) {
var_dump($e->getMessage());
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
throw $e;
}
} catch (Exception $e) {
var_dump($e->getMessage());
throw $e;
}
?>
--EXPECTF--
string(0) ""
string(0) ""
string(0) ""
string(0) ""
Fatal error: Uncaught Exception in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

@ -0,0 +1,21 @@
--TEST--
Testing exception and GOTO
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
goto foo;
try {
print 1;
foo:
print 2;
} catch (Exception $e) {
}
?>
--EXPECT--
2

@ -0,0 +1,13 @@
--TEST--
Throwing exception in global scope
--FILE--
<?php
throw new Exception(1);
?>
--EXPECTF--
Fatal error: Uncaught Exception: 1 in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

@ -0,0 +1,15 @@
--TEST--
Trying to throw a non-object
--SKIPIF--
<?php die('skip'); ?>
--FILE--
<?php
throw 1;
?>
--EXPECTF--
Fatal error: Uncaught Error: Can only throw objects in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

@ -0,0 +1,35 @@
--TEST--
Setting previous exception
--FILE--
<?php
try {
try {
throw new Exception("First", 1, new Exception("Another", 0, NULL));
}
catch (Exception $e) {
throw new Exception("Second", 2, $e);
}
}
catch (Exception $e) {
throw new Exception("Third", 3, $e);
}
?>
--EXPECTF--
Fatal error: Uncaught Exception: Another in %s
Stack trace:
#0 {main}
Next Exception: First in %s
Stack trace:
#0 {main}
Next Exception: Second in %s
Stack trace:
#0 {main}
Next Exception: Third in %s
Stack trace:
#0 {main}
thrown in %s

@ -0,0 +1,17 @@
--TEST--
Test exception doesn't cause RSHUTDOWN bypass, variation 0
--INI--
zend.assertions=1
--FILE--
<?php
define ("XXXXX", 1);
assert(false);
?>
--EXPECTF--
Fatal error: Uncaught AssertionError %s
Stack trace:
#0 [internal function]: assert(false)
#1 {main}
thrown in %s

@ -0,0 +1,20 @@
--TEST--
Exceptions on improper access to string
--FILE--
<?php
$s = "ABC";
try {
$s[] = "D";
} catch (Error $e) {
echo "\nException: " . $e->getMessage() . " in " , $e->getFile() . " on line " . $e->getLine() . "\n";
}
$s[] = "D";
?>
--EXPECTF--
Exception: [] operator not supported for strings in %s
Fatal error: Uncaught Error: [] operator not supported for strings %s
Stack trace:
#0 {main}
thrown in %s

@ -0,0 +1,14 @@
--TEST--
Testing throw exception doesn't crash with wrong params, variant 2
--FILE--
<?php
throw new Exception(new stdClass);
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Exception::__construct(): Argument #1 ($message) must be of type string, stdClass given in %s:%d
Stack trace:
#0 %s: Exception->__construct(Object(stdClass))
#1 {main}
thrown in %s on line %d

@ -0,0 +1,14 @@
--TEST--
Testing throw exception doesn't crash with wrong params, variant 4
--FILE--
<?php
throw new Error(new stdClass);
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Error::__construct(): Argument #1 ($message) must be of type string, stdClass given in %s:%d
Stack trace:
#0 %s: Error->__construct(Object(stdClass))
#1 {main}
thrown in %s on line %d

@ -0,0 +1,19 @@
--TEST--
XORing arrays
--FILE--
<?php
$a = array(1,2,3);
$b = array();
try {
$c = $a ^ $b;
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
echo "Done\n";
?>
--EXPECT--
Unsupported operand types: array ^ array
Done

@ -0,0 +1,39 @@
--TEST--
XORing strings
--FILE--
<?php
$s = "123";
$s1 = "234";
var_dump(bin2hex($s ^ $s1));
$s = "1235";
$s1 = "234";
var_dump(bin2hex($s ^ $s1));
$s = "some";
$s1 = "test";
var_dump(bin2hex($s ^ $s1));
$s = "some long";
$s1 = "test";
var_dump(bin2hex($s ^ $s1));
$s = "some";
$s1 = "test long";
var_dump(bin2hex($s ^ $s1));
$s = "some";
$s ^= "test long";
var_dump(bin2hex($s));
echo "Done\n";
?>
--EXPECT--
string(6) "030107"
string(6) "030107"
string(8) "070a1e11"
string(8) "070a1e11"
string(8) "070a1e11"
string(8) "070a1e11"
Done

@ -0,0 +1,19 @@
--TEST--
XORing booleans
--FILE--
<?php
$t = true;
$f = false;
var_dump($t ^ $f);
var_dump($t ^ $t);
var_dump($f ^ $f);
echo "Done\n";
?>
--EXPECT--
int(1)
int(0)
int(0)
Done

@ -0,0 +1,12 @@
--TEST--
Operator precedence
--FILE--
<?php
var_dump((object)1 instanceof stdClass);
var_dump(! (object)1 instanceof Exception);
?>
--EXPECT--
bool(true)
bool(true)
Loading…
Cancel
Save