diff --git a/.gitignore b/.gitignore index 11999b2a1a..f7ba966a49 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,9 @@ composer.lock vendor/ build/ + phpunit.xml +phpcs.xml # Ignore for all projects based on Zephir .temp/ @@ -52,6 +54,3 @@ runtime/run-tests.php runtime/a.zep runtime/index.php runtime/parser.out - -coverage.xml -clover.xml diff --git a/.travis.yml b/.travis.yml index 96a9d2135b..88201e2ea5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,22 @@ -language: php - -dist: trusty -# Change to `true' to enable debug mode sudo: false +language: php php: - - '5.5' - - '5.6' - - '7.0' - - '7.1' + - master + - '7.3' - '7.2' + - '7.1' + - '7.0' + - '5.6' git: depth: 1 -compiler: - - gcc - - clang +addons: + apt: + packages: + - gdb + - lcov env: global: @@ -24,40 +24,20 @@ env: - LIBRARY_PATH="$TRAVIS_BUILD_DIR/build/lib":$LIBRARY_PATH - C_INCLUDE_PATH="$TRAVIS_BUILD_DIR/build/include" - CFLAGS="-g3 -O0 -Wall -fvisibility=hidden" - - USE_ZEND_ALLOC=0 - - ZEND_DONT_UNLOAD_MODULES=1 - REPORT_EXIT_STATUS=1 - PATH="${HOME}/bin:${PATH}" - - RE2C_VERSION="1.0.3" + - RE2C_VERSION="1.1.1" - ZEPHIR_PARSER_VERSION="v1.1.2" - matrix: - - CC="gcc" - - CC="clang" + - DEFAULT_ZFLAGS="-Wnonexistent-function -Wnonexistent-class -Wunused-variable" + - DEFAULT_COMPOSER_FLAGS="--no-interaction --no-ansi --no-progress --no-suggest" + - REPORT_COVERAGE=1 matrix: fast_finish: true allow_failures: - - php: nightly - exclude: - - env: CC="gcc" - compiler: clang - - env: CC="clang" - compiler: gcc - include: - - env: CC="gcc" - php: nightly - compiler: gcc - - env: CC="clang" - php: nightly - compiler: clang - - env: CPPFLAGS=-DZEPHIR_RELEASE CC=gcc - php: '7.1' - - env: CPPFLAGS=-DZEPHIR_RELEASE CC=clang - php: '7.1' - - env: CPPFLAGS=-DZEPHIR_RELEASE CC=gcc - php: '7.2' - - env: CPPFLAGS=-DZEPHIR_RELEASE CC=clang - php: '7.2' + # There is still memory leaks + # and other issues like https://github.com/sebastianbergmann/phpunit/pull/3359 + - php: 'master' cache: apt: true @@ -71,74 +51,53 @@ cache: before_install: - if [[ ! -z "${GH_TOKEN}" ]]; then composer config github-oauth.github.com ${GH_TOKEN}; echo "Configured Github token"; fi; - - $CC --version - export PHP_MAJOR="$(`phpenv which php` -r 'echo phpversion();' | cut -d '.' -f 1)" - export PHP_MINOR="$(`phpenv which php` -r 'echo phpversion();' | cut -d '.' -f 2)" + - ulimit -c unlimited -S + - phpenv config-add ./unit-tests/ci/999-default.ini install: - - composer install --prefer-source --no-suggest - - bash ./unit-tests/ci/install-re2c $RE2C_VERSION - - bash ./unit-tests/ci/install_zephir_parser.sh + - travis_retry composer install $DEFAULT_COMPOSER_FLAGS + - travis_retry gem install coveralls-lcov + - ./unit-tests/ci/install-re2c.sh $RE2C_VERSION + - ./unit-tests/ci/install-zephir-parser.sh - ./install before_script: - - $(phpenv which php) compiler.php help - - $(phpenv which php) compiler.php generate -Wnonexistent-function -Wnonexistent-class -Wunused-variable - - $(phpenv which php) compiler.php stubs - - $(phpenv which php) compiler.php api - - | - ( - set -e - cd ext - $(phpenv which phpize) - ./configure --silent --with-php-config=$(phpenv which php-config) --enable-test - make -j"$(getconf _NPROCESSORS_ONLN)" - make --silent install - ) - #- ls -1 `$(phpenv which php-config) --extension-dir` - #- phpenv versions - - ulimit -c unlimited || true - # Uncomment to setting core dump - #- echo '/tmp/core_%e.%p' | sudo tee /proc/sys/kernel/core_pattern &> /dev/null - #- sudo chmod +s $(which gdb) + - ./unit-tests/ci/install-test-ext.sh script: - - echo -e 'variables_order=EGPCS\nenable_dl=true' >> "$(phpenv root)/versions/$(phpenv version-name)/etc/php.ini" - - vendor/bin/phpcs --standard=PSR2 --report=emacs --extensions=php --warning-severity=0 Library/ unit-tests/Extension/ unit-tests/Zephir/ - - | # Tests and coverage - ./unit-tests/phpunit \ - --not-exit \ - -c phpunit.xml.dist \ - --debug \ - unit-tests/ - - | # Check for memory leaks - valgrind \ - --read-var-info=yes \ - --error-exitcode=1 \ - --fullpath-after= \ - --track-origins=yes \ - --leak-check=full \ - --num-callers=20 \ - --run-libc-freeres=no \ - ./unit-tests/phpunit \ - --not-exit \ - -c phpunit.xml.dist \ - --no-coverage \ - unit-tests/ - - $(phpenv which php) unit-tests/microbench.php + - ./unit-tests/ci/run-unit-tests.sh + +jobs: + include: + - stage: Static Code Analysis + php: 7.2 + script: + - vendor/bin/phpcs + - stage: Compiller testing + php: 7.2 + compiler: clang + env: + - CC=clang + - REPORT_COVERAGE=0 + before_script: + - ./unit-tests/ci/install-test-ext.sh + script: + - ./unit-tests/ci/run-unit-tests.sh + - stage: Benchmark + php: 7.2 + before_script: + - ./unit-tests/ci/install-test-ext.sh + script: + - phpenv config-rm xdebug.ini || true + - $(phpenv which php) -d extension=ext/modules/test.so unit-tests/microbench.php after_success: - - if [[ ! -z "${CODECOV_TOKEN}" ]]; then bash <(curl -s https://codecov.io/bash); fi; + - ./unit-tests/ci/after-success.sh after_failure: - # Uncomment to debug core dump - # - ./unit-tests/ci/after_failure.sh - - $(phpenv which php) -v - - $(phpenv which php) -m - - $(phpenv which php) -i + - ./unit-tests/ci/after-failure.sh -addons: - apt: - packages: - - valgrind - - gdb +notifications: + email: false diff --git a/Library/Backends/ZendEngine2/Backend.php b/Library/Backends/ZendEngine2/Backend.php index 57c9e52003..3f6458eff7 100644 --- a/Library/Backends/ZendEngine2/Backend.php +++ b/Library/Backends/ZendEngine2/Backend.php @@ -620,9 +620,9 @@ protected function assignHelper($macro, $variableName, $value, CompilationContex $copyStr = ''; if ($doCopy === true) { $copyStr = ', 1'; - } else if ($doCopy === false) { + } elseif ($doCopy === false) { $copyStr = ', 0'; - } else if (isset($doCopy)) { + } elseif (isset($doCopy)) { $copyStr = ', ' . $doCopy; } @@ -644,9 +644,9 @@ protected function returnHelper($macro, $value, CompilationContext $context, $us $copyStr = ''; if ($doCopy === true) { $copyStr = ', 1'; - } else if ($doCopy === false) { + } elseif ($doCopy === false) { $copyStr = ', 0'; - } else if (isset($doCopy)) { + } elseif (isset($doCopy)) { $copyStr = ', ' . $doCopy; } @@ -736,7 +736,7 @@ public function addArrayEntry(Variable $variable, $key, $value, CompilationConte $keyType = 'assoc'; if (!isset($key)) { $keyType = 'append'; - } else if ($key instanceof CompiledExpression) { + } elseif ($key instanceof CompiledExpression) { $typeKey = $key->getType(); if ($typeKey == 'variable') { $var = $context->symbolTable->getVariableForRead($key->getCode(), $context); @@ -788,7 +788,7 @@ public function addArrayEntry(Variable $variable, $key, $value, CompilationConte } else { $valueStr = 'SL("' . $value->getCode() . '")'; } - } else if ($type == 'zval') { + } elseif ($type == 'zval') { $valueStr = $this->getVariableCode($value); } else { $valueStr = $value->getCode(); @@ -797,7 +797,7 @@ public function addArrayEntry(Variable $variable, $key, $value, CompilationConte if ($keyType == 'assoc') { $output = 'add_assoc_' . $type . '_ex(' . $this->getVariableCode($variable) . ', ' . $keyStr . ', ' . $valueStr . $doCopy . ');'; - } else if ($keyType == 'append') { + } elseif ($keyType == 'append') { $output = 'zephir_array_append(' . $this->getVariableCodePointer($variable) . ', ' . $this->resolveValue($value, $context) . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'; } else { $output = 'add_index_' . $type . '(' . $this->getVariableCode($variable) . ', ' . $keyStr . ', '. $valueStr . $doCopy . ');'; @@ -832,7 +832,7 @@ public function updateArray(Variable $symbolVariable, $key, $value, CompilationC default: throw new CompilerException('updateArray: Found a variable with unsupported type ' . $key->getType()); } - } else if ($key instanceof CompiledExpression) { + } elseif ($key instanceof CompiledExpression) { switch ($key->getType()) { case 'string': $compilationContext->codePrinter->output('zephir_array_update_string(' . $this->getVariableCodePointer($symbolVariable) . ', SL("' . $key->getCode() . '"), ' . $value . ', ' . $flags . ');'); @@ -924,7 +924,7 @@ public function arrayIsset(Variable $var, $resolvedExpr, $expression, Compilatio if ($resolvedExpr->getType() == 'int' || $resolvedExpr->getType() == 'long') { return new CompiledExpression('bool', 'zephir_array_isset_long(' . $this->getVariableCode($var) . ', ' . $this->getVariableCode($resolvedExpr) . ')', $expression); - } else if ($resolvedExpr->getType() == 'variable' || $resolvedExpr->getType() == 'string') { + } elseif ($resolvedExpr->getType() == 'variable' || $resolvedExpr->getType() == 'string') { return new CompiledExpression('bool', 'zephir_array_isset(' . $this->getVariableCode($var) . ', ' . $this->getVariableCode($resolvedExpr) . ')', $expression); } @@ -938,7 +938,7 @@ public function arrayIssetFetch(Variable $target, Variable $var, $resolvedExpr, if (!($resolvedExpr instanceof Variable)) { if ($resolvedExpr->getType() == 'string') { return new CompiledExpression('bool', 'zephir_array_isset_string_fetch(' . $code . ', SS("' . $resolvedExpr->getCode() . '"), '. $flags . ' TSRMLS_CC)', $expression); - } else if (in_array($resolvedExpr->getType(), array('int', 'uint', 'long'))) { + } elseif (in_array($resolvedExpr->getType(), array('int', 'uint', 'long'))) { return new CompiledExpression('bool', 'zephir_array_isset_long_fetch(' . $code . ', ' . $resolvedExpr->getCode() . ', ' . $flags . ' TSRMLS_CC)', $expression); } else { $resolvedExpr = $context->symbolTable->getVariableForRead($resolvedExpr->getCode(), $context); @@ -947,7 +947,7 @@ public function arrayIssetFetch(Variable $target, Variable $var, $resolvedExpr, if ($resolvedExpr->getType() == 'int' || $resolvedExpr->getType() == 'long') { return new CompiledExpression('bool', 'zephir_array_isset_long_fetch(' . $code . ', ' . $this->getVariableCode($resolvedExpr) . ', ' . $flags . ' TSRMLS_CC)', $expression); - } else if ($resolvedExpr->getType() == 'variable' || $resolvedExpr->getType() == 'string') { + } elseif ($resolvedExpr->getType() == 'variable' || $resolvedExpr->getType() == 'string') { return new CompiledExpression('bool', 'zephir_array_isset_fetch(' . $code . ', ' . $this->getVariableCode($resolvedExpr) . ', ' . $flags . ' TSRMLS_CC)', $expression); } throw new CompilerException('arrayIssetFetch [' . $resolvedExpr->getType() . ']', $expression); @@ -1133,17 +1133,17 @@ public function resolveValue($value, CompilationContext $context, $usePointer = { if ($value == 'null') { $value = ($usePointer ? '&' : '') . 'ZEPHIR_GLOBAL(global_null)'; - } else if ($value == 'true') { + } elseif ($value == 'true') { $value = ($usePointer ? '&' : '') . 'ZEPHIR_GLOBAL(global_true)'; - } else if ($value == 'false') { + } elseif ($value == 'false') { $value = ($usePointer ? '&' : '') . 'ZEPHIR_GLOBAL(global_false)'; - } else if ($value instanceof GlobalConstant) { + } elseif ($value instanceof GlobalConstant) { return ($usePointer ? '&' : '') . $value->getName(); - } else if ($value instanceof CompiledExpression) { + } elseif ($value instanceof CompiledExpression) { if ($value->getType() == 'array') { $var = $context->symbolTable->getVariableForWrite($value->getCode(), $context, null); $value = $usePointer ? $this->getVariableCodePointer($var) : $this->getVariableCode($var); - } else if ($value->getType() == 'variable') { + } elseif ($value->getType() == 'variable') { $value = $context->symbolTable->getVariableForWrite($value->getCode(), $context); } else { return $value->getCode(); @@ -1206,7 +1206,7 @@ public function callMethod($symbolVariable, Variable $variable, $methodName, $ca } if (!isset($symbolVariable)) { $context->codePrinter->output('ZEPHIR_' . $macro . '(NULL, ' . $variable->getName() . ', ' . $methodName . ', ' . $cachePointer . $paramStr . ');'); - } else if ($symbolVariable->getName() == 'return_value') { + } elseif ($symbolVariable->getName() == 'return_value') { $context->codePrinter->output('ZEPHIR_RETURN_' . $macro . '(' . $variable->getName() . ', ' . $methodName . ', ' . $cachePointer . $paramStr . ');'); } else { $context->codePrinter->output('ZEPHIR_' . $macro . '(&' . $symbolVariable->getName() . ', ' . $variable->getName() . ', ' . $methodName . ', ' . $cachePointer . $paramStr . ');'); @@ -1218,7 +1218,7 @@ public function callDynamicFunction($symbolVariable, Variable $variable, Compila $paramStr = $params != null ? ', ' . join(', ', $params) : ''; if (!isset($symbolVariable)) { $context->codePrinter->output('ZEPHIR_CALL_ZVAL_FUNCTION(NULL, ' . $this->getVariableCode($variable) . ', ' . $cache . ', ' . $cacheSlot . $paramStr . ');'); - } else if ($symbolVariable->getName() == 'return_value') { + } elseif ($symbolVariable->getName() == 'return_value') { $context->codePrinter->output('ZEPHIR_RETURN_CALL_ZVAL_FUNCTION(' . $this->getVariableCode($variable) . ', ' . $cache . ', ' . $cacheSlot . $paramStr . ');'); } else { $context->codePrinter->output('ZEPHIR_CALL_ZVAL_FUNCTION(' . $this->getVariableCodePointer($symbolVariable) . ', ' . $this->getVariableCode($variable) . ', ' . $cache . ', ' . $cacheSlot . $paramStr . ');'); diff --git a/Library/Backends/ZendEngine3/Backend.php b/Library/Backends/ZendEngine3/Backend.php index 803847c2cb..6f4c3bc325 100644 --- a/Library/Backends/ZendEngine3/Backend.php +++ b/Library/Backends/ZendEngine3/Backend.php @@ -409,7 +409,7 @@ public function addArrayEntry(Variable $variable, $key, $value, CompilationConte if (!isset($key)) { $keyType = 'append'; - } else if ($key instanceof CompiledExpression) { + } elseif ($key instanceof CompiledExpression) { $typeKey = $key->getType(); if ($typeKey == 'variable') { $var = $context->symbolTable->getVariableForRead($key->getCode(), $context); @@ -468,7 +468,7 @@ public function addArrayEntry(Variable $variable, $key, $value, CompilationConte } else { $valueStr = 'SL("' . $value->getCode() . '")'; } - } else if ($type == 'zval') { + } elseif ($type == 'zval') { $valueStr = $this->getVariableCode($value); } else { $valueStr = $value->getCode(); @@ -476,7 +476,7 @@ public function addArrayEntry(Variable $variable, $key, $value, CompilationConte if ($keyType == 'assoc') { $output = 'add_assoc_' . $type . '_ex(' . $this->getVariableCode($variable) . ', ' . $keyStr . ', ' . $valueStr . ');'; - } else if ($keyType == 'append') { + } elseif ($keyType == 'append') { $output = 'zephir_array_append(' . $this->getVariableCode($variable) . ', ' . $this->resolveValue($value, $context) . ', PH_SEPARATE, "' . Compiler::getShortUserPath($statement['file']) . '", ' . $statement['line'] . ');'; } else { $output = 'add_index_' . $type . '(' . $this->getVariableCode($variable) . ', ' . $keyStr . ', '. $valueStr . ');'; @@ -635,7 +635,7 @@ public function resolveValue($value, CompilationContext $context, $usePointer = if ($value instanceof CompiledExpression) { if ($value->getType() == 'array') { $value = $context->symbolTable->getVariableForWrite($value->getCode(), $context, null); - } else if ($value->getType() == 'variable') { + } elseif ($value->getType() == 'variable') { $value = $context->symbolTable->getVariableForWrite($value->getCode(), $context); } else { return $value->getCode(); @@ -679,7 +679,7 @@ public function callMethod($symbolVariable, Variable $variable, $methodName, $ca } if (!isset($symbolVariable)) { $context->codePrinter->output('ZEPHIR_' . $macro . '(NULL, ' . $this->getVariableCode($variable) . ', ' . $methodName . ', ' . $cachePointer . $paramStr . ');'); - } else if ($symbolVariable->getName() == 'return_value') { + } elseif ($symbolVariable->getName() == 'return_value') { $context->codePrinter->output('ZEPHIR_RETURN_' . $macro . '(' . $this->getVariableCode($variable) . ', ' . $methodName . ', ' . $cachePointer . $paramStr . ');'); } else { $symbol = $this->getVariableCode($symbolVariable); @@ -731,7 +731,7 @@ public function forStatement(Variable $exprVariable, $keyVariable, $variable, $d if (isset($keyVariable) && isset($variable)) { $macro = 'ZEND_HASH_' . $reverse . 'FOREACH_KEY_VAL'; $codePrinter->output($macro . '(Z_ARRVAL_P(' . $this->getVariableCode($exprVariable) . '), ' . $arrayNumKey->getName() . ', ' . $arrayStrKey->getName() . ', ' . $tempVariable->getName() . ')'); - } else if (isset($keyVariable)) { + } elseif (isset($keyVariable)) { $macro = 'ZEND_HASH_' . $reverse . 'FOREACH_KEY'; $codePrinter->output($macro . '(Z_ARRVAL_P(' . $this->getVariableCode($exprVariable) . '), ' . $arrayNumKey->getName() . ', ' . $arrayStrKey->getName() . ')'); } else { diff --git a/Library/Call.php b/Library/Call.php index 5600074321..b14c129917 100644 --- a/Library/Call.php +++ b/Library/Call.php @@ -377,7 +377,7 @@ public function getResolvedParams($parameters, CompilationContext $compilationCo $value = $compiledExpression->getCode(); if ($value == 'true') { $value = '1'; - } else if ($value == 'false') { + } elseif ($value == 'false') { $value = '0'; } $parameterVariable = $compilationContext->backend->getScalarTempVariable('variable', $compilationContext); diff --git a/Library/Compiler.php b/Library/Compiler.php index a8e3f89551..d3ec759cc8 100644 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -31,7 +31,7 @@ */ class Compiler { - const VERSION = '0.11.0'; + const VERSION = '0.11.1'; public $parserCompiled = false; @@ -866,7 +866,7 @@ public function generate(CommandInterface $command) * Load function optimizers */ if (self::$loadedPrototypes === false) { - FunctionCall::addOptimizerDir(ZEPHIRPATH . 'Library/Optimizers/FunctionCall'); + FunctionCall::addOptimizerDir(ZEPHIRPATH . '/Library/Optimizers/FunctionCall'); $optimizerDirs = $this->config->get('optimizer-dirs'); if (is_array($optimizerDirs)) { @@ -875,12 +875,12 @@ public function generate(CommandInterface $command) } } - if (is_dir(ZEPHIRPATH . 'prototypes') && is_readable(ZEPHIRPATH . 'prototypes')) { + if (is_dir(ZEPHIRPATH . '/prototypes') && is_readable(ZEPHIRPATH . '/prototypes')) { /** * Load additional extension prototypes * @var $file \DirectoryIterator */ - foreach (new \DirectoryIterator(ZEPHIRPATH . 'prototypes') as $file) { + foreach (new \DirectoryIterator(ZEPHIRPATH . '/prototypes') as $file) { if (!$file->isDir()) { $extension = str_replace('.php', '', $file); if (!extension_loaded($extension)) { diff --git a/Library/Documentation.php b/Library/Documentation.php index 5191b83def..b7471d6276 100644 --- a/Library/Documentation.php +++ b/Library/Documentation.php @@ -237,7 +237,7 @@ private function __findThemeDirectory($themeConfig, Config $config, CommandInter } else { $themesDirectories = array(); } - $themesDirectories[] = ZEPHIRPATH . "templates/Api/themes"; + $themesDirectories[] = ZEPHIRPATH . "/templates/Api/themes"; $this->themesDirectories = $themesDirectories; diff --git a/Library/Optimizers/FunctionCall/EvalOptimizer.php b/Library/Optimizers/FunctionCall/EvalOptimizer.php index dfb389d4f6..b7f9b39756 100644 --- a/Library/Optimizers/FunctionCall/EvalOptimizer.php +++ b/Library/Optimizers/FunctionCall/EvalOptimizer.php @@ -1,15 +1,13 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Zephir\Optimizers\FunctionCall; @@ -20,17 +18,22 @@ use Zephir\Optimizers\OptimizerAbstract; /** - * EvalOptimizer + * Zephir\Optimizers\FunctionCall\EvalOptimizer + * + * @package Zephir\Optimizers\FunctionCall */ class EvalOptimizer extends OptimizerAbstract { /** - * @param array $expression - * @param Call $call - * @param CompilationContext $context + * {@inheritdoc} * + * @param array $expression + * @param Call $call + * @param CompilationContext $context * @return bool|CompiledExpression|mixed + * * @throws CompilerException + * @throws \Zephir\Exception */ public function optimize(array $expression, Call $call, CompilationContext $context) { @@ -45,7 +48,10 @@ public function optimize(array $expression, Call $call, CompilationContext $cont $symbolVariable = $call->getSymbolVariable(true, $context); if ($symbolVariable->isNotVariableAndString()) { - throw new CompilerException("Returned values by functions can only be assigned to variant variables", $expression); + throw new CompilerException( + 'Returned values by functions can only be assigned to variant variables', + $expression + ); } $context->headersManager->add('kernel/fcall'); @@ -55,7 +61,16 @@ public function optimize(array $expression, Call $call, CompilationContext $cont if ($call->mustInitSymbolVariable()) { $symbolVariable->initVariant($context); } - $evalContext = str_replace(ZEPHIRPATH, '', $expression['file'] . ':' . $expression['line']); + + $evalContext = str_replace( + [ + ZEPHIRPATH . '\\', + ZEPHIRPATH . '/', + ], + '', + $expression['file'] . ':' . $expression['line'] + ); + $symbol = $context->backend->getVariableCode($symbolVariable); $context->codePrinter->output( sprintf('zephir_eval_php(%s, %s, "%s" TSRMLS_CC);', $resolvedParams[0], $symbol, $evalContext) diff --git a/Library/Statements/Let/ArrayIndex.php b/Library/Statements/Let/ArrayIndex.php index 51488b9f43..2a0b242536 100644 --- a/Library/Statements/Let/ArrayIndex.php +++ b/Library/Statements/Let/ArrayIndex.php @@ -195,19 +195,25 @@ protected function _assignArrayIndexSingle($variable, ZephirVariable $symbolVari /** * Compiles foo[y][x] = {expr} (multiple offset) * - * @param string $variable - * @param ZephirVariable $symbolVariable - * @param CompiledExpression $resolvedExpr - * @param CompilationContext $compilationContext - * @param array $statement + * @param string $variable + * @param ZephirVariable $symbolVariable + * @param CompiledExpression $resolvedExpr + * @param CompilationContext $compilationContext + * @param array $statement + * @return void * * @throws CompilerException + * @throws \Zephir\Exception */ - protected function _assignArrayIndexMultiple($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) - { - $codePrinter = $compilationContext->codePrinter; + protected function _assignArrayIndexMultiple( + $variable, + ZephirVariable $symbolVariable, + CompiledExpression $resolvedExpr, + CompilationContext $compilationContext, + $statement + ) { + $offsetExprs = []; - $offsetExprs = array(); foreach ($statement['index-expr'] as $indexExpr) { $expression = new Expression($indexExpr); $expression->setReadOnly(true); @@ -222,7 +228,13 @@ protected function _assignArrayIndexMultiple($variable, ZephirVariable $symbolVa case 'variable': break; default: - throw new CompilerException("Index: " . $exprIndex->getType() . " cannot be used as array index in assignment without cast", $indexExpr); + throw new CompilerException( + sprintf( + 'Index: %s cannot be used as array index in assignment without cast', + $exprIndex->getType() + ), + $indexExpr + ); } $offsetExprs[] = $exprIndex; @@ -234,9 +246,19 @@ protected function _assignArrayIndexMultiple($variable, ZephirVariable $symbolVa * Create a temporal zval (if needed) */ $symbolVariable = $this->_getResolvedArrayItem($resolvedExpr, $compilationContext); - $targetVariable = $compilationContext->symbolTable->getVariableForWrite($variable, $compilationContext, $statement); - $compilationContext->backend->assignArrayMulti($targetVariable, $symbolVariable, $offsetExprs, $compilationContext); + $targetVariable = $compilationContext->symbolTable->getVariableForWrite( + $variable, + $compilationContext, + $statement + ); + + $compilationContext->backend->assignArrayMulti( + $targetVariable, + $symbolVariable, + $offsetExprs, + $compilationContext + ); if ($symbolVariable->isTemporal()) { $symbolVariable->setIdle(true); diff --git a/Library/Statements/Let/ObjectDynamicProperty.php b/Library/Statements/Let/ObjectDynamicProperty.php index d3f444985c..ce0704c2c6 100644 --- a/Library/Statements/Let/ObjectDynamicProperty.php +++ b/Library/Statements/Let/ObjectDynamicProperty.php @@ -99,7 +99,7 @@ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpres $value = null; if ($resolvedExpr->getBooleanCode() == '1') { $value = 'true'; - } else if ($resolvedExpr->getBooleanCode() == '0') { + } elseif ($resolvedExpr->getBooleanCode() == '0') { $value = 'false'; } else { throw new \Exception('?'); diff --git a/Library/Statements/Let/ObjectDynamicStringProperty.php b/Library/Statements/Let/ObjectDynamicStringProperty.php index 9a3892ef4e..f9372977aa 100644 --- a/Library/Statements/Let/ObjectDynamicStringProperty.php +++ b/Library/Statements/Let/ObjectDynamicStringProperty.php @@ -95,7 +95,7 @@ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpres case 'bool': if ($resolvedExpr->getBooleanCode() == '1') { $value = 'true'; - } else if ($resolvedExpr->getBooleanCode() == '0') { + } elseif ($resolvedExpr->getBooleanCode() == '0') { $value = 'false'; } else { throw new \Exception("?"); diff --git a/Library/Utils.php b/Library/Utils.php index 34409d0236..263d56ea1b 100644 --- a/Library/Utils.php +++ b/Library/Utils.php @@ -46,7 +46,6 @@ public static function addSlashes($str, $escapeSlash = false) { $newstr = ""; $after = null; - $before = null; $length = strlen($str); for ($i = 0; $i < $length; $i++) { $ch = substr($str, $i, 1); @@ -82,8 +81,7 @@ public static function addSlashes($str, $escapeSlash = false) case "\\": $newstr .= $ch . $after; $i++; - $before = null; - continue; + break; default: $newstr .= "\\\\"; break; @@ -92,7 +90,6 @@ public static function addSlashes($str, $escapeSlash = false) default: $newstr .= $ch; } - $before = $ch; } return $newstr; } diff --git a/appveyor.yml b/appveyor.yml index ab4df1421d..913a5f304e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.11.0-{build} +version: 0.11.1-{build} environment: matrix: @@ -98,8 +98,7 @@ build_script: test_script: - cd %APPVEYOR_BUILD_FOLDER% - - 'php unit-tests/phpunit -c phpunit.xml.dist --not-exit --debug unit-tests/' - - 'php unit-tests/microbench.php' + - 'php unit-tests/phpunit -c phpunit.xml.dist unit-tests/' on_success: - ps: PrintBuildDetails diff --git a/bootstrap.php b/bootstrap.php index d916d993eb..6d6d064f1b 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -31,10 +31,10 @@ define('T', "\t"); define('2T', "\t\t"); -if (file_exists(ZEPHIRPATH . 'vendor/autoload.php')) { - require ZEPHIRPATH . 'vendor/autoload.php'; +if (file_exists(ZEPHIRPATH . '/vendor/autoload.php')) { + require ZEPHIRPATH . '/vendor/autoload.php'; } else { - require ZEPHIRPATH . 'Library/Loader.php'; + require ZEPHIRPATH . '/Library/Loader.php'; Zephir\Loader::register(); } diff --git a/composer.json b/composer.json index 29e477c884..cb4f925492 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "ext-ctype": "*", "ext-hash": "*", "ext-json": "*", - "ext-xml": "*" + "ext-xml": "*", + "ext-mbstring": "*" }, "require-dev": { "ext-gmp": "*", @@ -39,6 +40,17 @@ "Zephir\\": "Library" } }, + "autoload-dev": { + "psr-4": { + "Zephir\\Stubs\\": "unit-tests/Zephir/Stubs/", + "Zephir\\Test\\": "unit-tests/Zephir/Test/", + "Zephir\\Support\\": "unit-tests/Zephir/Support/", + "Extension\\": "unit-tests/Extension/" + }, + "classmap": [ + "unit-tests/Data/" + ] + }, "bin": [ "bin/zephir" ], diff --git a/kernels/ZendEngine2/README.md b/kernels/ZendEngine2/README.md index 3890dd71de..3655db1053 100644 --- a/kernels/ZendEngine2/README.md +++ b/kernels/ZendEngine2/README.md @@ -29,8 +29,4 @@ Zephir Kernel provides you: License ------- -Zephir is open-sourced software licensed under the New BSD License. See the LICENSE file for more information. - -Related Documentation ---------------------- -* http://internals.phalconphp.com/en/latest/index.html \ No newline at end of file +Zephir is open-sourced software licensed under the New MIT License. See the LICENSE file for more information. diff --git a/kernels/ZendEngine3/README.md b/kernels/ZendEngine3/README.md index 3890dd71de..3655db1053 100644 --- a/kernels/ZendEngine3/README.md +++ b/kernels/ZendEngine3/README.md @@ -29,8 +29,4 @@ Zephir Kernel provides you: License ------- -Zephir is open-sourced software licensed under the New BSD License. See the LICENSE file for more information. - -Related Documentation ---------------------- -* http://internals.phalconphp.com/en/latest/index.html \ No newline at end of file +Zephir is open-sourced software licensed under the New MIT License. See the LICENSE file for more information. diff --git a/kernels/ZendEngine3/array.c b/kernels/ZendEngine3/array.c index 1e6289a849..707f62765e 100644 --- a/kernels/ZendEngine3/array.c +++ b/kernels/ZendEngine3/array.c @@ -53,12 +53,44 @@ void ZEPHIR_FASTCALL zephir_create_array(zval *return_value, uint size, int init } } +/** + * Simple convenience function which ensures that you are dealing with an array and you can + * eliminate noise from your code. + * + * It's a bit strange but the refcount for an empty array is always zero somehow. + * There is another strange phenomenon: these zvals does not have any type_flag value. + * Thus we should recreate a new empty array so that it has correct refcount + * value and type_flag. This magic behavior was introduced since PHP 7.3. + * + * Steps to reproduce: + * + * Userland: + * $object->method([10 => []]); + * + * Zephir: + * public function method(array p) + * { + * let p[10]["str"] = "foo"; + * } + */ +void +ZEPHIR_FASTCALL zephir_ensure_array(zval *zv) +{ + if ( + Z_TYPE_P(zv) == IS_ARRAY && + zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0 && + (!Z_REFCOUNTED_P(zv) || Z_REFCOUNT_P(zv) < 1) + ) { + zephir_create_array(zv, 0, 0); + } +} + int zephir_array_isset_fetch(zval *fetched, const zval *arr, zval *index, int readonly) { HashTable *h; zval *result; - if (Z_TYPE_P(arr) != IS_ARRAY) { + if (UNEXPECTED(Z_TYPE_P(arr) != IS_ARRAY)) { ZVAL_NULL(fetched); return 0; @@ -94,11 +126,14 @@ int zephir_array_isset_fetch(zval *fetched, const zval *arr, zval *index, int re } if (result != NULL) { + zephir_ensure_array(result); + if (!readonly) { ZVAL_COPY(fetched, result); } else { ZVAL_COPY_VALUE(fetched, result); } + return 1; } @@ -107,12 +142,14 @@ int zephir_array_isset_fetch(zval *fetched, const zval *arr, zval *index, int re return 0; } -int zephir_array_isset_string_fetch(zval *fetched, zval *arr, char *index, uint index_length, int readonly) +int zephir_array_isset_string_fetch(zval *fetched, const zval *arr, char *index, uint index_length, int readonly) { zval *zv; if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) { if ((zv = zend_hash_str_find(Z_ARRVAL_P(arr), index, index_length)) != NULL) { + zephir_ensure_array(zv); + if (!readonly) { ZVAL_COPY(fetched, zv); } else { @@ -127,12 +164,14 @@ int zephir_array_isset_string_fetch(zval *fetched, zval *arr, char *index, uint return 0; } -int zephir_array_isset_long_fetch(zval *fetched, zval *arr, unsigned long index, int readonly) +int zephir_array_isset_long_fetch(zval *fetched, const zval *arr, unsigned long index, int readonly) { zval *zv; if (EXPECTED(Z_TYPE_P(arr) == IS_ARRAY)) { if ((zv = zend_hash_index_find(Z_ARRVAL_P(arr), index)) != NULL) { + zephir_ensure_array(zv); + if (!readonly) { ZVAL_COPY(fetched, zv); } else { @@ -161,7 +200,7 @@ int ZEPHIR_FASTCALL zephir_array_isset(const zval *arr, zval *index) return zend_hash_str_exists(h, SL("")); case IS_DOUBLE: - return zend_hash_index_exists(h, (ulong)Z_DVAL_P(index));; + return zend_hash_index_exists(h, (ulong)Z_DVAL_P(index)); case IS_TRUE: case IS_FALSE: @@ -398,7 +437,7 @@ int zephir_array_fetch_long(zval *return_value, zval *arr, unsigned long index, return SUCCESS; } if ((flags & PH_NOISY) == PH_NOISY) { - zend_error(E_NOTICE, "Undefined index: %s", index); + zend_error(E_NOTICE, "Undefined index: %lu", index); } } else { if ((flags & PH_NOISY) == PH_NOISY) { @@ -420,8 +459,7 @@ int zephir_array_fetch_long(zval *return_value, zval *arr, unsigned long index, */ void zephir_merge_append(zval *left, zval *values) { - - zval *tmp; + zval *tmp; if (Z_TYPE_P(left) != IS_ARRAY) { zend_error(E_NOTICE, "First parameter of zephir_merge_append must be an array"); @@ -503,7 +541,6 @@ int zephir_array_update_zval(zval *arr, zval *index, zval *value, int flags) int zephir_array_update_string(zval *arr, const char *index, uint index_length, zval *value, int flags) { - zval *zv; if (Z_TYPE_P(arr) != IS_ARRAY) { zend_error(E_WARNING, "Cannot use a scalar value as an array (3)"); @@ -511,50 +548,42 @@ int zephir_array_update_string(zval *arr, const char *index, uint index_length, } if ((flags & PH_CTOR) == PH_CTOR) { - zval new_zv; - //Z_TRY_DELREF_P(value); //? - ZVAL_DUP(&new_zv, value); - value = &new_zv; + zval new_value; + + ZVAL_DUP(&new_value, value); + value = &new_value; + } else if ((flags & PH_COPY) == PH_COPY) { + Z_TRY_ADDREF_P(value); } if ((flags & PH_SEPARATE) == PH_SEPARATE) { SEPARATE_ZVAL_IF_NOT_REF(arr); } - if ((flags & PH_COPY) == PH_COPY) { - Z_TRY_ADDREF_P(value); - } - - zv = zend_hash_str_update(Z_ARRVAL_P(arr), index, index_length, value); - return zv != NULL ? SUCCESS : FAILURE; + return zend_hash_str_update(Z_ARRVAL_P(arr), index, index_length, value) ? SUCCESS : FAILURE; } int zephir_array_update_long(zval *arr, unsigned long index, zval *value, int flags ZEPHIR_DEBUG_PARAMS) { - zval *zv; - if (Z_TYPE_P(arr) != IS_ARRAY) { zend_error(E_WARNING, "Cannot use a scalar value as an array in %s on line %d", file, line); return FAILURE; } if ((flags & PH_CTOR) == PH_CTOR) { - zval new_zv; - //Z_TRY_DELREF_P(value); //? - ZVAL_DUP(&new_zv, value); - value = &new_zv; + zval new_value; + + ZVAL_DUP(&new_value, value); + value = &new_value; + } else if ((flags & PH_COPY) == PH_COPY) { + Z_TRY_ADDREF_P(value); } if ((flags & PH_SEPARATE) == PH_SEPARATE) { SEPARATE_ZVAL_IF_NOT_REF(arr); } - if ((flags & PH_COPY) == PH_COPY) { - Z_TRY_ADDREF_P(value); - } - - zv = zend_hash_index_update(Z_ARRVAL_P(arr), index, value); - return zv != NULL ? SUCCESS : FAILURE; + return zend_hash_index_update(Z_ARRVAL_P(arr), index, value) ? SUCCESS : FAILURE; } void zephir_array_keys(zval *return_value, zval *input) diff --git a/kernels/ZendEngine3/array.h b/kernels/ZendEngine3/array.h index 9b024b8f92..b61c0ed5bc 100644 --- a/kernels/ZendEngine3/array.h +++ b/kernels/ZendEngine3/array.h @@ -29,10 +29,16 @@ void ZEPHIR_FASTCALL zephir_create_array(zval *return_value, uint size, int initialize); +/** + * Simple convenience function which ensures that you are dealing with an array and you can + * eliminate noise from your code. + */ +void ZEPHIR_FASTCALL zephir_ensure_array(zval *probable_array); + /** Combined isset/fetch */ int zephir_array_isset_fetch(zval *fetched, const zval *arr, zval *index, int readonly); -int zephir_array_isset_string_fetch(zval *fetched, zval *arr, char *index, uint index_length, int readonly); -int zephir_array_isset_long_fetch(zval *fetched, zval *arr, unsigned long index, int readonly); +int zephir_array_isset_string_fetch(zval *fetched, const zval *arr, char *index, uint index_length, int readonly); +int zephir_array_isset_long_fetch(zval *fetched, const zval *arr, unsigned long index, int readonly); /** Check for index existence */ int ZEPHIR_FASTCALL zephir_array_isset(const zval *arr, zval *index); diff --git a/kernels/ZendEngine3/fcall.c b/kernels/ZendEngine3/fcall.c index 49d8ae6e20..1a2f273c3a 100644 --- a/kernels/ZendEngine3/fcall.c +++ b/kernels/ZendEngine3/fcall.c @@ -211,11 +211,16 @@ static void resolve_callable(zval* retval, zephir_call_type type, zend_class_ent static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, zend_class_entry* ce, zval *this_ptr, zval *func, zend_class_entry* called_scope) { zend_class_entry* calling_scope; + +#if PHP_VERSION_ID < 70300 fcic->initialized = 0; +#endif fcic->function_handler = NULL; if (type == zephir_fcall_function && Z_TYPE_P(func) == IS_STRING) { +#if PHP_VERSION_ID < 70300 fcic->initialized = 1; +#endif fcic->called_scope = NULL; fcic->calling_scope = NULL; fcic->object = NULL; @@ -276,7 +281,9 @@ static void populate_fcic(zend_fcall_info_cache* fcic, zephir_call_type type, ze return; } +#if PHP_VERSION_ID < 70300 fcic->initialized = 1; +#endif } /** @@ -295,7 +302,6 @@ int zephir_call_user_function(zval *object_pp, zend_class_entry *obj_ce, zephir_ int key_ok = FAILURE; zephir_fcall_cache_entry *temp_cache_entry = NULL; zval callable; - int i; zend_class_entry* called_scope = zend_get_called_scope(EG(current_execute_data)); assert(obj_ce || !object_pp); @@ -316,7 +322,8 @@ int zephir_call_user_function(zval *object_pp, zend_class_entry *obj_ce, zephir_ key_ok = zephir_make_fcall_key((zend_string*)fcall_key, type, (object_pp && type != zephir_fcall_ce ? Z_OBJCE_P(object_pp) : obj_ce), function_name, called_scope); if (SUCCESS == key_ok) { zend_string* zs = (zend_string*)fcall_key; - GC_REFCOUNT(zs) = 1; + + GC_SET_REFCOUNT(zs, 1); GC_TYPE_INFO(zs) = IS_STRING; temp_cache_entry = zend_hash_find_ptr(zephir_globals_ptr->fcache, zs); @@ -338,7 +345,10 @@ int zephir_call_user_function(zval *object_pp, zend_class_entry *obj_ce, zephir_ fci.params = NULL; fci.no_separation = 1; +#if PHP_VERSION_ID < 70300 fcic.initialized = 0; +#endif + if (cache_entry && *cache_entry) { /* We have a cache record, initialize scope */ populate_fcic(&fcic, type, obj_ce, object_pp, function_name, called_scope); @@ -354,41 +364,25 @@ int zephir_call_user_function(zval *object_pp, zend_class_entry *obj_ce, zephir_ zend_is_callable_ex(&callable, fci.object, IS_CALLABLE_CHECK_SILENT, NULL, &fcic, NULL); } +#if PHP_VERSION_ID < 70300 if (!fcic.initialized) { resolve_callable(&callable, type, (object_pp && type != zephir_fcall_ce ? Z_OBJCE_P(object_pp) : obj_ce), object_pp, function_name); ZVAL_COPY_VALUE(&fci.function_name, &callable); } +#endif #ifdef _MSC_VER zval *p = emalloc(sizeof(zval) * (fci.param_count + 1)); #else zval p[fci.param_count]; #endif - for (i=0; iname)); - } - fprintf(stderr, "> %s called: %p, calling: %p, obj: %p, h: %p, type=%d\n", Z_STRVAL(tmp), fcic.called_scope, fcic.calling_scope, fcic.object, fcic.function_handler, (int)type); -#endif status = zend_call_function(&fci, &fcic); -#if 0 - fprintf(stderr, "< called: %p, calling: %p, obj: %p, h: %p\n", fcic.called_scope, fcic.calling_scope, fcic.object, fcic.function_handler); -#endif - #ifdef _MSC_VER efree(p); #endif @@ -401,7 +395,12 @@ int zephir_call_user_function(zval *object_pp, zend_class_entry *obj_ce, zephir_ * call failed OR there was an exception (to be safe) OR cache key is not defined OR * fcall cache was deinitialized OR we have a slot cache */ - if (EXPECTED(status != FAILURE) && !EG(exception) && SUCCESS == key_ok && fcic.initialized && !temp_cache_entry) { + int initialized = 1; +#if PHP_VERSION_ID < 70300 + initialized = fcic.initialized; +#endif + + if (EXPECTED(status != FAILURE) && !EG(exception) && SUCCESS == key_ok && initialized && !temp_cache_entry) { zephir_fcall_cache_entry *cache_entry_temp = fcic.function_handler; if (cache_entry) { diff --git a/kernels/ZendEngine3/file.c b/kernels/ZendEngine3/file.c index dece46425d..11dfe67898 100644 --- a/kernels/ZendEngine3/file.c +++ b/kernels/ZendEngine3/file.c @@ -251,13 +251,16 @@ void zephir_file_put_contents(zval *return_value, zval *filename, zval *data) } switch (Z_TYPE_P(data)) { - case IS_NULL: case IS_LONG: case IS_DOUBLE: case IS_TRUE: case IS_FALSE: +#if PHP_VERSION_ID < 70300 case IS_CONSTANT: +#else + case IS_CONSTANT_AST: +#endif use_copy = zend_make_printable_zval(data, ©); if (use_copy) { data = © diff --git a/kernels/ZendEngine3/math.c b/kernels/ZendEngine3/math.c index 1f71a614b0..489fb5da9c 100644 --- a/kernels/ZendEngine3/math.c +++ b/kernels/ZendEngine3/math.c @@ -189,9 +189,10 @@ void zephir_round(zval *return_value, zval *op1, zval *op2, zval *op3) } } -long zephir_mt_rand(long min, long max) +zend_long +zephir_mt_rand(zend_long min, zend_long max) { - long number; + zend_long number; if (max < min) { php_error_docref(NULL, E_WARNING, "max(%ld) is smaller than min(%ld)", max, min); @@ -202,8 +203,18 @@ long zephir_mt_rand(long min, long max) php_mt_srand(GENERATE_SEED()); } - number = (long) (php_mt_rand() >> 1); + number = (zend_long) (php_mt_rand() >> 1); + + /** + * The RAND_RANGE() macro has been removed since PHP 7.3. + * php_mt_rand_range() should be used instead. + * However, php_mt_rand_range() has been present since PHP 7.1. + */ +#if PHP_VERSION_ID < 70100 RAND_RANGE(number, min, max, PHP_MT_RAND_MAX); +#else + number = php_mt_rand_range(min, max); +#endif return number; } diff --git a/kernels/ZendEngine3/math.h b/kernels/ZendEngine3/math.h index 61fed53386..6b4272a08c 100644 --- a/kernels/ZendEngine3/math.h +++ b/kernels/ZendEngine3/math.h @@ -31,7 +31,7 @@ double zephir_acos(zval *op1); double zephir_sqrt(zval *op1); double zephir_floor(zval *op1); -long zephir_mt_rand(long min, long max); +zend_long zephir_mt_rand(zend_long min, zend_long max); double zephir_ceil(zval *op1); void zephir_round(zval *return_value, zval *op1, zval *op2, zval *op3); diff --git a/kernels/ZendEngine3/memory.c b/kernels/ZendEngine3/memory.c index fae632c431..7de519e45b 100644 --- a/kernels/ZendEngine3/memory.c +++ b/kernels/ZendEngine3/memory.c @@ -237,6 +237,7 @@ int ZEPHIR_FASTCALL zephir_memory_restore_stack(const char *func) fprintf(stderr, "The frame was created by %s\n", zephir_globals_ptr->active_memory->func); fprintf(stderr, "Calling function: %s\n", func); zephir_print_backtrace(); + return FAILURE; } zephir_memory_restore_stack_common(zephir_globals_ptr); diff --git a/kernels/ZendEngine3/memory.h b/kernels/ZendEngine3/memory.h index 902d79a2e2..d50802ee62 100644 --- a/kernels/ZendEngine3/memory.h +++ b/kernels/ZendEngine3/memory.h @@ -164,3 +164,10 @@ int zephir_set_symbol_str(char *key_name, unsigned int key_length, zval *value); } while (0) #endif + +/* Backwards compatibility for GC API change in PHP 7.3 */ +#if PHP_VERSION_ID < 70300 +# define GC_ADDREF(p) ++GC_REFCOUNT(p) +# define GC_DELREF(p) --GC_REFCOUNT(p) +# define GC_SET_REFCOUNT(p, rc) GC_REFCOUNT(p) = rc +#endif diff --git a/kernels/ZendEngine3/object.c b/kernels/ZendEngine3/object.c index 086759b74b..7da30c6ff4 100644 --- a/kernels/ZendEngine3/object.c +++ b/kernels/ZendEngine3/object.c @@ -26,6 +26,7 @@ #include "php_ext.h" #include +#include #include "kernel/main.h" #include "kernel/memory.h" @@ -353,14 +354,13 @@ int zephir_clone(zval *destination, zval *obj) clone_call = Z_OBJ_HT_P(obj)->clone_obj; if (!clone_call) { if (ce) { - php_error_docref(NULL, E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); + php_error_docref(NULL, E_ERROR, "Trying to clone an uncloneable object of class %s", ZSTR_VAL(ce->name)); } else { php_error_docref(NULL, E_ERROR, "Trying to clone an uncloneable object"); } status = FAILURE; } else { if (!EG(exception)) { - //zval_ptr_dtor(destination); ZVAL_OBJ(destination, clone_call(obj)); if (EG(exception)) { zval_ptr_dtor(destination); @@ -1166,7 +1166,9 @@ int zephir_create_instance(zval *return_value, const zval *class_name) fci.no_separation = 1; ZVAL_NULL(&fci.function_name); +#if PHP_VERSION_ID < 70300 fcc.initialized = 1; +#endif fcc.object = obj; fcc.called_scope = ce; fcc.calling_scope = ce; @@ -1228,7 +1230,9 @@ int zephir_create_instance_params(zval *return_value, const zval *class_name, zv fci.no_separation = 1; ZVAL_NULL(&fci.function_name); +#if PHP_VERSION_ID < 70300 fcc.initialized = 1; +#endif fcc.object = obj; fcc.called_scope = ce; fcc.calling_scope = ce; diff --git a/kernels/ZendEngine3/require.c b/kernels/ZendEngine3/require.c index 722dd2ee4e..c9be4c94c6 100644 --- a/kernels/ZendEngine3/require.c +++ b/kernels/ZendEngine3/require.c @@ -40,9 +40,18 @@ int zephir_require_ret(zval *return_value_ptr, const char *require_path) { zend_file_handle file_handle; - int ret; zend_op_array *new_op_array; zval dummy, local_retval; + char realpath[MAXPATHLEN]; + int ret; + + if (UNEXPECTED(!VCWD_REALPATH(require_path, realpath))) { +#ifndef ZEPHIR_RELEASE + fprintf(stderr, "%s: Failed opening file %s", __func__, require_path); + zephir_print_backtrace(); +#endif + return FAILURE; + } ZVAL_UNDEF(&local_retval); @@ -54,11 +63,6 @@ int zephir_require_ret(zval *return_value_ptr, const char *require_path) } #endif - /* if (!memcmp(require_path, "", 0)) { - @TODO, throw an exception here - return FAILURE; - } */ - file_handle.filename = require_path; file_handle.free_filename = 0; file_handle.type = ZEND_HANDLE_FILENAME; diff --git a/kernels/ZendEngine3/string.c b/kernels/ZendEngine3/string.c index 3a4d67ca1f..f8e16db4ea 100644 --- a/kernels/ZendEngine3/string.c +++ b/kernels/ZendEngine3/string.c @@ -1302,7 +1302,11 @@ void zephir_addslashes(zval *return_value, zval *str) } } +#if PHP_VERSION_ID < 70300 ZVAL_STR(return_value, php_addslashes(Z_STR_P(str), 0)); +#else + ZVAL_STR(return_value, php_addslashes(Z_STR_P(str))); +#endif if (UNEXPECTED(use_copy)) { zval_dtor(©); diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000000..487a98ed69 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,45 @@ + + + + + Check the code of the sniffs in Zephir. + + + + + + + + + + + + + + + + + + + + + Library + + + diff --git a/phpunit-php-73.xml.dist b/phpunit-php-73.xml.dist new file mode 100644 index 0000000000..df01b0acc9 --- /dev/null +++ b/phpunit-php-73.xml.dist @@ -0,0 +1,31 @@ + + + + + + + ./unit-tests/Extension + + + ./unit-tests/Zephir + + + + + + ./Library + + + + + + + + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 623824f009..49613fe5f7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -24,21 +24,14 @@ + - - - + diff --git a/test/exists.zep b/test/exists.zep index 1bc16769ef..672f8c9cb4 100644 --- a/test/exists.zep +++ b/test/exists.zep @@ -3,22 +3,22 @@ namespace Test; class Exists { - public function testClassExists(var className, bool autoload=true) + public function testClassExists(var className, bool autoload=true) -> bool { return class_exists(className, autoload); } - public function testInterfaceExists(var interfaceName, bool autoload=true) + public function testInterfaceExists(var interfaceName, bool autoload=true) -> bool { return interface_exists(interfaceName, autoload); } - public function testMethodExists(var obj, var methodName) + public function testMethodExists(var obj, var methodName) -> bool { return method_exists(obj, methodName); } - public function testFileExists(var fileName) + public function testFileExists(var fileName) -> bool { return file_exists(fileName); } diff --git a/test/exitdie.zep b/test/exitdie.zep index 0d7f759a47..f7ab30dd8f 100644 --- a/test/exitdie.zep +++ b/test/exitdie.zep @@ -2,22 +2,21 @@ namespace Test; class ExitDie { - - public function testExit(param = "") + public function testExit(var param = null) -> void { - if typeof param == "string" && param == "" { + if empty(param) { exit(); - } else { - exit(param); } + + exit(param); } - public function testDie(param = "") + public function testDie(var param = null) -> void { - if typeof param == "string" && param == "" { + if empty(param) { die(); - } else { - die(param); } + + die(param); } } diff --git a/test/instance.zep b/test/instance.zep index 21a19cbf64..6ca2953866 100644 --- a/test/instance.zep +++ b/test/instance.zep @@ -24,7 +24,7 @@ class Instance } - public static function testIssue1339() + public static function testIssue1339() -> { var parameters; @@ -45,7 +45,7 @@ class Instance return create_instance_params("Test\\Instance", parameters); } - public static function testInstanceCreate(string className) + public static function testInstanceCreate(string className) -> { return create_instance(className); } diff --git a/test/nativearray.zep b/test/nativearray.zep index b3bcb88916..c2cc939633 100644 --- a/test/nativearray.zep +++ b/test/nativearray.zep @@ -1,55 +1,50 @@ - -/** - * Control Flow - */ - namespace Test; class NativeArray { - public function testArray1() + public function testArray1() -> array { var a; let a = []; return a; } - public function testArray2() + public function testArray2() -> array { var a; let a = [1, 2, 3]; return a; } - public function testArray3() + public function testArray3() -> array { var a; let a = [1.1, 2.2, 3.3]; return a; } - public function testArray4() + public function testArray4() -> array { var a; let a = [false, true, false]; return a; } - public function testArray5() + public function testArray5() -> array { var a; let a = [null, null, null]; return a; } - public function testArray6() + public function testArray6() -> array { var a; let a = ["x", "y", "z"]; return a; } - public function testArray7() + public function testArray7() -> array { var d; int a, b, c; let a = 1, b = 2, c = 3; @@ -57,7 +52,7 @@ class NativeArray return d; } - public function testArray8() + public function testArray8() -> array { var d; double a, b, c; let a = 1, b = 2, c = 3; @@ -65,7 +60,7 @@ class NativeArray return d; } - public function testArray9() + public function testArray9() -> array { var d; boolean a, b, c; let a = true, b = false, c = true; @@ -73,7 +68,7 @@ class NativeArray return d; } - public function testArray10() + public function testArray10() -> array { var d; string a, b, c; let a = "hello1", b = "hello2", c = "hello3"; @@ -81,7 +76,7 @@ class NativeArray return d; } - public function testArray11() + public function testArray11() -> array { var a, b, c; let a = [1, 2, 3]; @@ -90,7 +85,7 @@ class NativeArray return c; } - public function testArray12() + public function testArray12() -> array { var a, b, c; let a = [1, 2, 3]; @@ -99,77 +94,77 @@ class NativeArray return c; } - public function testArray13() + public function testArray13() -> array { var a; let a = [1: "hello1", 2: "hello2", 3: "hello3"]; return a; } - public function testArray14() + public function testArray14() -> array { var a; let a = ["hello1": 1, "hello2": 2, "hello3": 3]; return a; } - public function testArray15() + public function testArray15() -> array { var a; let a = ["hello1": true, "hello2": false, "hello3": true]; return a; } - public function testArray16() + public function testArray16() -> array { var a; let a = ["hello1": 1.0, "hello2": 2.0, "hello3": 3.0]; return a; } - public function testArray17() + public function testArray17() -> array { var a; let a = ["hello1": null, "hello2": null, "hello3": null]; return a; } - public function testArray18() + public function testArray18() -> array { var a; let a = ["hello1": "a", "hello2": "b", "hello3": "c"]; return a; } - public function testArray19() + public function testArray19() -> array { var a; let a = [0: true, 1: false, 2: true]; return a; } - public function testArray20() + public function testArray20() -> array { var a; let a = [0: 1.0, 1: 2.0, 2: 3.0]; return a; } - public function testArray21() + public function testArray21() -> array { var a; let a = [0: null, 1: null, 2: null]; return a; } - public function testArray22() + public function testArray22() -> array { var a; let a = [0: 4, 1: 5, 2: 6]; return a; } - public function testArray23() + public function testArray23() -> array { var a; int b; @@ -178,7 +173,7 @@ class NativeArray return a; } - public function testArray24() + public function testArray24() -> array { var a; double b; @@ -187,7 +182,7 @@ class NativeArray return a; } - public function testArray25() + public function testArray25() -> array { var a; boolean b; @@ -196,7 +191,7 @@ class NativeArray return a; } - public function testArray26() + public function testArray26() -> array { var a; var b; @@ -205,7 +200,7 @@ class NativeArray return a; } - public function testArray27() + public function testArray27() -> array { var a; string b; @@ -214,7 +209,7 @@ class NativeArray return a; } - public function testArray28() + public function testArray28() -> array { var a; string b; @@ -223,7 +218,7 @@ class NativeArray return a; } - public function testArray29() + public function testArray29() -> array { var a; long b; @@ -232,7 +227,7 @@ class NativeArray return a; } - public function testArray30() + public function testArray30() -> array { var a; string b; @@ -241,7 +236,7 @@ class NativeArray return a; } - public function testArrayAccess1() + public function testArrayAccess1() -> array { var a, b; @@ -250,7 +245,7 @@ class NativeArray return b; } - public function testArrayAccess2() + public function testArrayAccess2() -> array { var a, b; @@ -260,7 +255,7 @@ class NativeArray return b; } - public function testArrayAccess3() + public function testArrayAccess3() -> array { var a, b; long c; @@ -272,7 +267,7 @@ class NativeArray return b; } - public function testArrayAccess4() + public function testArrayAccess4() -> array { var a, b; string c; @@ -284,7 +279,7 @@ class NativeArray return b; } - public function testArrayAccess5() + public function testArrayAccess5() -> array { var a, b, c; @@ -295,7 +290,7 @@ class NativeArray return b; } - public function testArrayAccess6() + public function testArrayAccess6() -> array { var a, b; @@ -305,7 +300,7 @@ class NativeArray return b; } - public function testArrayMultipleAccess1() + public function testArrayMultipleAccess1() -> array { var a, b; @@ -315,7 +310,7 @@ class NativeArray return b; } - public function testArrayMultipleAccess2() + public function testArrayMultipleAccess2() -> array { var a, b; @@ -325,7 +320,7 @@ class NativeArray return b; } - public function testArrayMultipleAccess3() + public function testArrayMultipleAccess3() -> array { var a, b; @@ -335,7 +330,7 @@ class NativeArray return b; } - public function testArrayMultipleAccess4() + public function testArrayMultipleAccess4() -> array { var a, b; @@ -345,7 +340,7 @@ class NativeArray return b; } - public function testArrayMultipleAccess5() + public function testArrayMultipleAccess5() -> array { var a, b; @@ -355,14 +350,14 @@ class NativeArray return b; } - public function testArrayUpdate1() + public function testArrayUpdate1() -> array { var a; let a = [1, 2, 3], a[0] = 4; return a; } - public function testArrayUpdate2() + public function testArrayUpdate2() -> array { var a; int b; let a = [1, 2, 3], @@ -371,7 +366,7 @@ class NativeArray return a; } - public function testArrayUpdate3() + public function testArrayUpdate3() -> array { var a; int b; let a = [1, 2, 3], @@ -382,14 +377,14 @@ class NativeArray return a; } - public function testArrayUpdate4() + public function testArrayUpdate4() -> array { var a; let a = ["a": 1, "b": 2, "c": 3], a["a"] = 4; return a; } - public function testArrayUpdate5() + public function testArrayUpdate5() -> array { var a; let a = [1, 2, 3], @@ -399,21 +394,21 @@ class NativeArray return a; } - public function testArrayAppend1() + public function testArrayAppend1() -> array { var a; let a = [], a[] = "hello", a[] = null, a[] = false, a[] = 1.10, a[] = 5, a[] = [1, 2, 3]; return a; } - public function testArrayAppend2() + public function testArrayAppend2() -> array { var a; string b = "hello"; var c = null; boolean d = false; double e = 1.10; int f = 5; var g = [1, 2, 3]; let a = [], a[] = b, a[] = c, a[] = d, a[] = e, a[] = f, a[] = g; return a; } - public function testMultipleArrayUpdate1() + public function testMultipleArrayUpdate1() -> array { var a; @@ -422,7 +417,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate2() + public function testMultipleArrayUpdate2() -> array { var a; @@ -431,7 +426,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate3() + public function testMultipleArrayUpdate3() -> array { var a; @@ -440,7 +435,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate4() + public function testMultipleArrayUpdate4() -> array { var a; @@ -449,7 +444,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate5() + public function testMultipleArrayUpdate5() -> array { var a; @@ -458,7 +453,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate6() + public function testMultipleArrayUpdate6() -> array { var a; @@ -467,7 +462,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate7() + public function testMultipleArrayUpdate7() -> array { var a; @@ -478,7 +473,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate8() + public function testMultipleArrayUpdate8() -> array { var a; @@ -490,7 +485,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate9() + public function testMultipleArrayUpdate9() -> array { var a; @@ -502,7 +497,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate10() + public function testMultipleArrayUpdate10() -> array { var a; @@ -514,7 +509,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate11() + public function testMultipleArrayUpdate11() -> array { var a, b = "y", c = "x"; @@ -523,7 +518,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate12() + public function testMultipleArrayUpdate12() -> array { var a, b = "y", c = "x", d = "z"; @@ -532,7 +527,7 @@ class NativeArray return a; } - public function testMultipleArrayUpdate13() + public function testMultipleArrayUpdate13() -> array { var a; array b, c, d; @@ -546,21 +541,21 @@ class NativeArray return a; } - public function testMultipleArrayAppend1() + public function testMultipleArrayAppend1() -> array { var a = []; var b = "y"; let a[0]["hello"][b][] = null; return a; } - public function testMultipleArrayAppend2() + public function testMultipleArrayAppend2() -> array { var a = []; int b = 100; string x = "hello"; let a[0]["hello"][b][x][] = null; return a; } - public function testMultipleArrayAppend3() + public function testMultipleArrayAppend3() -> array { var a = []; var b = "y"; let a[0]["hello"][b] = null; @@ -571,19 +566,12 @@ class NativeArray return a; } - public function testArrayWrongUpdate1() - { - var x, y; - let x = [], y = "hello"; - let x[y] = new \stdClass; - } - - public function testArrayKeys(var param) + public function testArrayKeys(var param) -> array { return array_keys(param); } - public function testImplodeArray(var param) + public function testImplodeArray(var param) -> string { return implode("|", array_keys(param)); } @@ -591,22 +579,22 @@ class NativeArray /** * @link https://github.com/phalcon/zephir/issues/110 */ - public function issue110() + public function issue110()-> string { var byteUnits; let byteUnits = ["B": 0, "K": 10, "M": 20, "G": 30, "T": 40, "KB": 10, "MB": 20, "GB": 30, "TB": 40]; return implode("|", array_keys(byteUnits)); } - public function issue264(array tokens) + public function issue264(array tokens) -> bool { return !isset(tokens[1]); } - public function issue743a(array current) -> array + public function issue743a(array current743a) -> array { - let current[42]["str"] = "ok"; - return current; + let current743a[42]["str"] = "ok"; + return current743a; } public function issue743b(array current) -> array @@ -626,7 +614,7 @@ class NativeArray /** * @link https://github.com/phalcon/zephir/issues/709 */ - public function issue709() + public function issue709() -> bool { var c, arr; var works = true; diff --git a/test/requires.zep b/test/requires.zep index 40ee5d5af9..9de587fbc8 100644 --- a/test/requires.zep +++ b/test/requires.zep @@ -7,7 +7,7 @@ class Requires { protected content; - public function requireExternal1(var path) + public function requireExternal1(var path) -> var { return require path; } @@ -18,17 +18,20 @@ class Requires return true; } - public function requireExternal3(var path) + public function requireExternal3(var path) -> var { var external3; - create_symbol_table(); + if PHP_MAJOR_VERSION == 5 { + create_symbol_table(); + } + let external3 = new External3(); external3->req(path, this); return this->content; } - public function setContent(var content) + public function setContent(var content) -> void { let this->content = content; } diff --git a/test/requires/External3.zep b/test/requires/External3.zep index 185ae18434..c50ff38068 100644 --- a/test/requires/External3.zep +++ b/test/requires/External3.zep @@ -9,11 +9,10 @@ class External3 { protected someVariable; - public function req(var path, var requires) + public function req(var path, var requires) -> void { ob_clean(); require path; requires->setContent(ob_get_contents()); - ob_clean(); } } diff --git a/unit-tests/Data/TestAbstractClass.php b/unit-tests/Data/TestAbstractClass.php index 06dec38af3..240a2c3286 100644 --- a/unit-tests/Data/TestAbstractClass.php +++ b/unit-tests/Data/TestAbstractClass.php @@ -1,6 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + abstract class TestAbstractClass { - } diff --git a/unit-tests/Data/TestExClass.php b/unit-tests/Data/TestExClass.php index 92a12491c6..c10224c7b9 100644 --- a/unit-tests/Data/TestExClass.php +++ b/unit-tests/Data/TestExClass.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + class TestExClass { } diff --git a/unit-tests/Data/TestExInterface.php b/unit-tests/Data/TestExInterface.php index 4de8413aea..03a82e22eb 100644 --- a/unit-tests/Data/TestExInterface.php +++ b/unit-tests/Data/TestExInterface.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + interface TestExInterface { } diff --git a/unit-tests/Extension/CastTest.php b/unit-tests/Extension/CastTest.php index dbb9760d3f..50b03b5999 100644 --- a/unit-tests/Extension/CastTest.php +++ b/unit-tests/Extension/CastTest.php @@ -121,7 +121,7 @@ public function testResourceCast() ); } - $file = fopen(__DIR__ . '/php/exists.php', 'r'); + $file = fopen(__DIR__ . '/../fixtures/exists.php', 'r'); $this->assertEquals((int) STDIN, $this->test->testCastStdinToInteger()); $this->assertEquals((int) STDOUT, $this->test->testCastStdoutToInteger()); diff --git a/unit-tests/Extension/ExistsTest.php b/unit-tests/Extension/ExistsTest.php index 9c6c073e16..42d01f28f4 100644 --- a/unit-tests/Extension/ExistsTest.php +++ b/unit-tests/Extension/ExistsTest.php @@ -1,43 +1,40 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Extension; use Test\Exists; -require DATA_PATH . '/TestExClass.php'; -require DATA_PATH . '/TestExInterface.php'; +use PHPUnit\Framework\TestCase; -class ExistsTest extends \PHPUnit_Framework_TestCase +class ExistsTest extends TestCase { public function testAssertations() { $t = new Exists(); - $this->assertTrue($t->testClassExists('TestExClass')); + $this->assertTrue($t->testClassExists(\TestExClass::class)); $this->assertFalse($t->testClassExists('TestExClassx')); - $this->assertFalse($t->testClassExists('TestExInterface')); + $this->assertFalse($t->testClassExists(\TestExInterface::class)); // with namespace - $this->assertTrue($t->testClassExists('\\Test\\Exists')); + $this->assertTrue($t->testClassExists(Exists::class)); // class not interface - $this->assertFalse($t->testInterfaceExists('TestExClass')); - $this->assertTrue($t->testInterfaceExists('TestExInterface')); + $this->assertFalse($t->testInterfaceExists(\TestExClass::class)); + $this->assertTrue($t->testInterfaceExists(\TestExInterface::class)); $this->assertFalse($t->testInterfaceExists('TestExInterfacex')); $this->assertTrue($t->testMethodExists($t, 'testMethodExists')); - $this->assertTrue($t->testFileExists(__DIR__ . '/php/exists.php')); + $this->assertTrue($t->testFileExists(__DIR__ . '/../fixtures/exists.php')); $this->assertFalse($t->testFileExists(__DIR__ . '/php/existsxxxx.php')); } } diff --git a/unit-tests/Extension/ExitDieTest.php b/unit-tests/Extension/ExitDieTest.php index a363dc0bb1..d480314eb3 100644 --- a/unit-tests/Extension/ExitDieTest.php +++ b/unit-tests/Extension/ExitDieTest.php @@ -1,43 +1,137 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Extension; -class ExitDieTest extends \PHPUnit_Framework_TestCase +use Zephir\Support\TestCase; +use PHPUnit\Framework\SkippedTestError; + +class ExitDieTest extends TestCase { - public function testExitDie() + /** @var string */ + private $phpBinary; + + /** + * {@inheritdoc} + * + * @return void + */ + public static function setUpBeforeClass() + { + if (PHP_VERSION_ID >= 70300) { + throw new SkippedTestError("Skip test on unstable PHP versions"); + } + } + + /** + * {@inheritdoc} + * + * @return void + */ + public function setUp() { - $phpBinary = constant('PHP_BINARY'); + $this->phpBinary = constant('PHP_BINARY'); /* If we use phpdbg, you need to add options -qrr */ if (defined('PHP_SAPI') && constant('PHP_SAPI') == 'phpdbg') { - $phpBinary .= ' -qrr'; + $this->phpBinary .= ' -qrr'; + } + + $this->phpBinary .= " -d 'enable_dl=true'"; + $extension = realpath( __DIR__ . '/../../ext/modules/test.so'); + + if (file_exists($extension)) { + $this->phpBinary .= sprintf(" -d 'extension=%s'", $extension); } - $phpBinary .= " -d 'enable_dl=true'"; + parent::setUp(); + } + + /** @test */ + public function shouldExitWthoutAnyMessage() + { + $testfile = __DIR__ . '/../fixtures/exit.php'; + $command = "$this->phpBinary $testfile"; + $output = []; + + exec($command, $output, $exitStatus); + + $this->assertEmpty($output, sprintf( + 'Exit message does not match with expected value. Output was: %s. Executed command: %s', + $this->prepareOutput($output), + $command + )); - $testfile1 = __DIR__ .'/fixtures/exit.php'; - $return1 = `$phpBinary $testfile1`; - $this->assertSame('', trim($return1)); + $this->assertSame(0, $exitStatus, sprintf( + 'Exit code does not match with expected value. Output was: %s. Executed command: %s', + $this->prepareOutput($output), + $command + )); + } - $arg = 'Hello World'; - $testfile2 = __DIR__ .'/fixtures/exit_string.php'; - $return2 = `$phpBinary $testfile2 "$arg"`; - $this->assertSame($arg, trim($return2)); + /** @test */ + public function shouldExitWthProvidedStatusMessage() + { + $testfile = __DIR__ . '/../fixtures/exit_string.php'; + $statusMessage = 'Hello World'; + $command = "$this->phpBinary $testfile \"$statusMessage\""; + $output = []; + + exec($command, $output, $exitStatus); + + $this->assertSame($statusMessage, $output[0], sprintf( + 'Exit message does not match with expected value. Output was: %s. Executed command: %s', + $this->prepareOutput($output), + $command + )); + + $this->assertSame(0, $exitStatus, sprintf( + 'Exit code does not match with expected value. Output was: %s. Executed command: %s', + $this->prepareOutput($output), + $command + )); + } + + /** @test */ + public function shouldExitWthProvidedStatusCode() + { + $testfile = __DIR__ . '/../fixtures/exit_int.php'; + $statusCode = 220; + $command = "$this->phpBinary $testfile $statusCode"; + $output = []; + + exec($command, $output, $exitStatus); + + $this->assertEmpty($output, sprintf( + 'Exit message does not match with expected value. Output was: %s. Executed command: %s', + $this->prepareOutput($output), + $command + )); + + $this->assertSame($statusCode, $exitStatus, sprintf( + 'Exit code does not match with expected value. Output was: %s. Executed command: %s', + $this->prepareOutput($output), + $command + )); + } + + private function prepareOutput($output) + { + if (empty($output)) { + return '(empty output)'; + } + + if (isset($output[0]) && !empty($output[0])) { + return $output[0]; + } - $testfile3 = __DIR__ .'/fixtures/exit_int.php'; - $intArg = 128; - $cmd3 = "$phpBinary $testfile3 $intArg"; - exec($cmd3, $out3, $return3); - $this->assertSame($return3, $intArg); + return json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); } } diff --git a/unit-tests/Extension/ExtendedInterfaceTest.php b/unit-tests/Extension/ExtendedInterfaceTest.php index 470d6673a7..cff21c36ed 100644 --- a/unit-tests/Extension/ExtendedInterfaceTest.php +++ b/unit-tests/Extension/ExtendedInterfaceTest.php @@ -13,13 +13,23 @@ namespace Extension; -class ExtendedInterfaceTest extends \PHPUnit_Framework_TestCase +use Test\ExtendedInterface; +use PHPUnit\Framework\TestCase; + +class ExtendedInterfaceTest extends TestCase { - public function testCheckInterfaceExtending() + /** @test */ + public function shouldExtendsInterfaces() { - $refl = new \ReflectionClass('Test\\ExtendedInterface'); - $this->assertTrue($refl->isInterface()); - $this->assertContains('IteratorAggregate', $refl->getInterfaceNames()); - $this->assertContains('Countable', $refl->getInterfaceNames()); + try { + $reflection = new \ReflectionClass(ExtendedInterface::class); + } catch (\ReflectionException $e) { + $this->fail($e->getMessage()); + return; + } + + $this->assertTrue($reflection->isInterface()); + $this->assertContains('IteratorAggregate', $reflection->getInterfaceNames()); + $this->assertContains('Countable', $reflection->getInterfaceNames()); } } diff --git a/unit-tests/Extension/FcallTest.php b/unit-tests/Extension/FcallTest.php index 9779b72c97..fc2fbb3b84 100644 --- a/unit-tests/Extension/FcallTest.php +++ b/unit-tests/Extension/FcallTest.php @@ -76,6 +76,6 @@ public function testFunctionDeclaration() $this->assertSame("ab", zephir_global_method_test("ab/c")); $this->assertInstanceOf(\stdClass::class, \Test\zephir_namespaced_method_with_type_casting(new \stdClass())); - $this->assertInstanceOf(\stdClass::class, zephir_global_method_with_type_casting(new \stdClass())); + $this->assertInstanceOf(\stdClass::class, \zephir_global_method_with_type_casting(new \stdClass())); } } diff --git a/unit-tests/Extension/Globals/EnvTest.php b/unit-tests/Extension/Globals/EnvTest.php index bfb4ba91e3..55422306dc 100644 --- a/unit-tests/Extension/Globals/EnvTest.php +++ b/unit-tests/Extension/Globals/EnvTest.php @@ -27,7 +27,7 @@ public function setUp() if (strpos(ini_get('variables_order'), 'E') === false) { $this->markTestSkipped( - "variables_order ini directive does not contain 'E'." . + "variables_order ini directive does not contain 'E'. " . "Make sure you have set variables_order to 'EGPCS' in php.ini." ); } diff --git a/unit-tests/Extension/InstanceTest.php b/unit-tests/Extension/InstanceTest.php index dfda8b4f86..ac24730ee4 100644 --- a/unit-tests/Extension/InstanceTest.php +++ b/unit-tests/Extension/InstanceTest.php @@ -1,43 +1,37 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Extension; -use Error; use Test\Instance; +use PHPUnit\Framework\TestCase; -require DATA_PATH . '/TestAbstractClass.php'; - -class InstanceTest extends \PHPUnit_Framework_TestCase +class InstanceTest extends TestCase { public function testIssue1339() { - $t = Instance::testIssue1339(); - $this->assertInstanceOf("Test\\Instance", $t); + $this->assertInstanceOf(Instance::class, Instance::testIssue1339()); } - public function testInstanceAbstract() + /** + * @test + * @expectedException \Error + * @expectedExceptionMessage Cannot instantiate abstract class TestAbstractClass + */ + public function shouldThrowErrorOnInstantiateAbstractClass() { if (PHP_VERSION_ID < 70000) { - $this->markTestSkipped( - "We can't catch fatal errors on php 5.x" - ); + $this->markTestSkipped("We can't catch fatal errors on php 5.x"); } - try { - $t = Instance::testInstanceCreate(\TestAbstractClass::class); - } catch (Error $e) { - $this->assertEquals("Cannot instantiate abstract class TestAbstractClass", $e->getMessage()); - } + Instance::testInstanceCreate(\TestAbstractClass::class); } } diff --git a/unit-tests/Extension/Issue1404Test.php b/unit-tests/Extension/Issue1404Test.php index 039f4617e1..c6e5e523bf 100644 --- a/unit-tests/Extension/Issue1404Test.php +++ b/unit-tests/Extension/Issue1404Test.php @@ -13,12 +13,12 @@ namespace Extension; -use \Test\Issue1404; - if (version_compare(PHP_VERSION, '5.6', '<')) { require_once('Issue1404TestTrait55.php'); + class_alias('\Extension\Issue1404TestTrait55', '\Extension\Issue1404TestTrait'); } else { require_once('Issue1404TestTrait56.php'); + class_alias('\Extension\Issue1404TestTrait56', '\Extension\Issue1404TestTrait'); } /** diff --git a/unit-tests/Extension/Issue1404TestTrait55.php b/unit-tests/Extension/Issue1404TestTrait55.php index 914aa1e846..ebc1f92cae 100644 --- a/unit-tests/Extension/Issue1404TestTrait55.php +++ b/unit-tests/Extension/Issue1404TestTrait55.php @@ -21,7 +21,7 @@ * @license MIT http://zephir-lang.com/license.html * @link https://github.com/phalcon/zephir/issues/1404 */ -trait Issue1404TestTrait +trait Issue1404TestTrait55 { protected function onNotSuccessfulTest(\Exception $error) { diff --git a/unit-tests/Extension/Issue1404TestTrait56.php b/unit-tests/Extension/Issue1404TestTrait56.php index e102b5554e..9f8a0c7117 100644 --- a/unit-tests/Extension/Issue1404TestTrait56.php +++ b/unit-tests/Extension/Issue1404TestTrait56.php @@ -21,7 +21,7 @@ * @license MIT http://zephir-lang.com/license.html * @link https://github.com/phalcon/zephir/issues/1404 */ -trait Issue1404TestTrait +trait Issue1404TestTrait56 { protected function onNotSuccessfulTest($error) { diff --git a/unit-tests/Extension/NativeArrayTest.php b/unit-tests/Extension/NativeArrayTest.php index 6a13c3d130..a17720edb0 100644 --- a/unit-tests/Extension/NativeArrayTest.php +++ b/unit-tests/Extension/NativeArrayTest.php @@ -14,145 +14,147 @@ namespace Extension; use Test\NativeArray; +use PHPUnit\Framework\TestCase; -class NativeArrayTest extends \PHPUnit_Framework_TestCase +class NativeArrayTest extends TestCase { public function testArray() { $t = new NativeArray(); - $this->assertSame($t->testArray1(), array()); - $this->assertSame($t->testArray2(), array(1, 2, 3)); - $this->assertSame($t->testArray3(), array(1.1, 2.2, 3.3)); - $this->assertSame($t->testArray4(), array(false, true, false)); - $this->assertSame($t->testArray5(), array(null, null, null)); - $this->assertSame($t->testArray6(), array("x", "y", "z")); - $this->assertSame($t->testArray7(), array(1, 2, 3)); - $this->assertSame($t->testArray8(), array(1.0, 2.0, 3.0)); - $this->assertSame($t->testArray9(), array(true, false, true)); - $this->assertSame($t->testArray10(), array("hello1", "hello2", "hello3")); - $this->assertSame($t->testArray11(), array(array(1, 2, 3), array(4, 5, 6))); - $this->assertSame($t->testArray12(), array(array(array(1, 2, 3)))); - $this->assertSame($t->testArray13(), array(1 => "hello1", 2 => "hello2", 3 => "hello3")); - $this->assertSame($t->testArray14(), array("hello1" => 1, "hello2" => 2, "hello3" => 3)); - $this->assertSame($t->testArray15(), array("hello1" => true, "hello2" => false, "hello3" => true)); - $this->assertSame($t->testArray16(), array("hello1" => 1.0, "hello2" => 2.0, "hello3" => 3.0)); - $this->assertSame($t->testArray17(), array("hello1" => null, "hello2" => null, "hello3" => null)); - $this->assertSame($t->testArray18(), array("hello1" => "a", "hello2" => "b", "hello3" => "c")); - $this->assertSame($t->testArray19(), array(0 => true, 1 => false, 2 => true)); - $this->assertSame($t->testArray20(), array(0 => 1.0, 1 => 2.0, 2 => 3.0)); - $this->assertSame($t->testArray21(), array(0 => null, 1 => null, 2 => null)); - $this->assertSame($t->testArray22(), array(0 => 4, 1 => 5, 2 => 6)); - $this->assertSame($t->testArray23(), array(0 => 0, 1 => 0, 2 => 0)); - $this->assertSame($t->testArray24(), array(0 => 0.0, 1 => 0.0, 2 => 0.0)); + $this->assertSame([], $t->testArray1()); + $this->assertSame([1, 2, 3], $t->testArray2()); + $this->assertSame([1.1, 2.2, 3.3], $t->testArray3()); + $this->assertSame([false, true, false], $t->testArray4()); + $this->assertSame([null, null, null], $t->testArray5()); + $this->assertSame(["x", "y", "z"], $t->testArray6()); + $this->assertSame([1, 2, 3], $t->testArray7()); + $this->assertSame([1.0, 2.0, 3.0], $t->testArray8()); + $this->assertSame([true, false, true], $t->testArray9()); + $this->assertSame(["hello1", "hello2", "hello3"], $t->testArray10()); + $this->assertSame([[1, 2, 3], [4, 5, 6]], $t->testArray11()); + $this->assertSame([[[1, 2, 3]]], $t->testArray12()); + $this->assertSame([1 => "hello1", 2 => "hello2", 3 => "hello3"], $t->testArray13()); + $this->assertSame(["hello1" => 1, "hello2" => 2, "hello3" => 3], $t->testArray14()); + $this->assertSame(["hello1" => true, "hello2" => false, "hello3" => true], $t->testArray15()); + $this->assertSame(["hello1" => 1.0, "hello2" => 2.0, "hello3" => 3.0], $t->testArray16()); + $this->assertSame(["hello1" => null, "hello2" => null, "hello3" => null], $t->testArray17()); + $this->assertSame(["hello1" => "a", "hello2" => "b", "hello3" => "c"], $t->testArray18()); + $this->assertSame([0 => true, 1 => false, 2 => true], $t->testArray19()); + $this->assertSame([0 => 1.0, 1 => 2.0, 2 => 3.0], $t->testArray20()); + $this->assertSame([0 => null, 1 => null, 2 => null], $t->testArray21()); + $this->assertSame([0 => 4, 1 => 5, 2 => 6], $t->testArray22()); + $this->assertSame([0 => 0, 1 => 0, 2 => 0], $t->testArray23()); + $this->assertSame([0 => 0.0, 1 => 0.0, 2 => 0.0], $t->testArray24()); } public function testArrayAccess() { $t = new NativeArray(); - $this->assertSame($t->testArrayAccess1(), 1); - $this->assertSame($t->testArrayAccess2(), 1); - $this->assertSame($t->testArrayAccess3(), 1); - $this->assertSame($t->testArrayAccess4(), 1); - $this->assertSame($t->testArrayAccess5(), 1); + $this->assertSame(1, $t->testArrayAccess1()); + $this->assertSame(1, $t->testArrayAccess2()); + $this->assertSame(1, $t->testArrayAccess3()); + $this->assertSame(1, $t->testArrayAccess4()); + $this->assertSame(1, $t->testArrayAccess5()); } public function testArrayMultipleAccess() { $t = new NativeArray(); - $this->assertSame($t->testArrayMultipleAccess1(), "a"); - $this->assertSame($t->testArrayMultipleAccess2(), "b"); - $this->assertSame($t->testArrayMultipleAccess3(), "b"); - $this->assertSame($t->testArrayMultipleAccess4(), "b"); - $this->assertSame($t->testArrayMultipleAccess5(), 0); + $this->assertSame("a", $t->testArrayMultipleAccess1()); + $this->assertSame("b", $t->testArrayMultipleAccess2()); + $this->assertSame("b", $t->testArrayMultipleAccess3()); + $this->assertSame("b", $t->testArrayMultipleAccess4()); + $this->assertSame(0, $t->testArrayMultipleAccess5()); } public function testArrayUpdate() { $t = new NativeArray(); - $this->assertSame($t->testArrayUpdate1(), array(4, 2, 3)); - $this->assertSame($t->testArrayUpdate2(), array(4, 2, 3)); - $this->assertSame($t->testArrayUpdate3(), array(4, 5, 3)); - $this->assertSame($t->testArrayUpdate4(), array("a" => 4, "b" => 2, "c" => 3)); + $this->assertSame([4, 2, 3], $t->testArrayUpdate1()); + $this->assertSame([4, 2, 3], $t->testArrayUpdate2()); + $this->assertSame([4, 5, 3], $t->testArrayUpdate3()); + $this->assertSame(["a" => 4, "b" => 2, "c" => 3], $t->testArrayUpdate4()); } public function testMultipleArrayUpdate() { $t = new NativeArray(); - $this->assertSame($t->testMultipleArrayUpdate1(), array('x' => array('y' => null))); - $this->assertSame($t->testMultipleArrayUpdate2(), array('x' => array('y' => array('z' => null)))); - $this->assertSame($t->testMultipleArrayUpdate3(), array(0 => array(1 => null))); - $this->assertSame($t->testMultipleArrayUpdate4(), array(0 => array(1 => array(2 => null)))); - $this->assertSame($t->testMultipleArrayUpdate5(), array('a' => array(1 => array('c' => null)))); - $this->assertSame($t->testMultipleArrayUpdate6(), array(0 => array('b' => array(2 => null)))); - $this->assertSame($t->testMultipleArrayUpdate7(), array('a' => array(1 => array('c' => true)), 0 => array('b' => array(2 => false)))); - $this->assertSame($t->testMultipleArrayUpdate8(), array('a' => array(0 => null, 1 => true, 2 => false))); - $this->assertSame($t->testMultipleArrayUpdate9(), array('a' => array(0 => null, 1 => false))); - $this->assertSame($t->testMultipleArrayUpdate10(), array('a' => array(0 => null, 1 => array('c' => false)))); - $this->assertSame($t->testMultipleArrayUpdate11(), array('y' => array('x' => null))); - $this->assertSame($t->testMultipleArrayUpdate12(), array('y' => array('x' => array('z' => null)))); + $this->assertSame(['x' => ['y' => null]], $t->testMultipleArrayUpdate1()); + $this->assertSame(['x' => ['y' => ['z' => null]]], $t->testMultipleArrayUpdate2()); + $this->assertSame([0 => [1 => null]], $t->testMultipleArrayUpdate3()); + $this->assertSame([0 => [1 => [2 => null]]], $t->testMultipleArrayUpdate4()); + $this->assertSame(['a' => [1 => ['c' => null]]], $t->testMultipleArrayUpdate5()); + $this->assertSame([0 => ['b' => [2 => null]]], $t->testMultipleArrayUpdate6()); + $this->assertSame(['a' => [1 => ['c' => true]], 0 => ['b' => [2 => false]]], $t->testMultipleArrayUpdate7()); + $this->assertSame(['a' => [0 => null, 1 => true, 2 => false]], $t->testMultipleArrayUpdate8()); + $this->assertSame(['a' => [0 => null, 1 => false]], $t->testMultipleArrayUpdate9()); + $this->assertSame(['a' => [0 => null, 1 => ['c' => false]]], $t->testMultipleArrayUpdate10()); + $this->assertSame(['y' => ['x' => null]], $t->testMultipleArrayUpdate11()); + $this->assertSame(['y' => ['x' => ['z' => null]]], $t->testMultipleArrayUpdate12()); } public function testArrayKeys() { $t = new NativeArray(); - $this->assertSame($t->testArrayKeys(array('test1' => 1, 'test2' => 2, 'test3' => 3)), array('test1', 'test2', 'test3')); - $this->assertSame($t->testArrayKeys(array(1, 2, 3, 4, 5, 6)), array(0, 1, 2, 3, 4, 5)); + $this->assertSame(['test1', 'test2', 'test3'], $t->testArrayKeys(['test1' => 1, 'test2' => 2, 'test3' => 3])); + $this->assertSame([0, 1, 2, 3, 4, 5], $t->testArrayKeys([1, 2, 3, 4, 5, 6])); } public function testImplodeArray() { $t = new NativeArray(); - $this->assertSame($t->testImplodeArray(array('test1' => 1, 'test2' => 2, 'test3' => 3)), 'test1|test2|test3'); + $this->assertSame('test1|test2|test3', $t->testImplodeArray(['test1' => 1, 'test2' => 2, 'test3' => 3])); } public function testIssue110() { $t = new NativeArray(); - $this->assertSame($t->issue110(), 'B|K|M|G|T|KB|MB|GB|TB'); + $this->assertSame('B|K|M|G|T|KB|MB|GB|TB', $t->issue110()); } public function testIssue264() { $t = new NativeArray(); - $this->assertFalse($t->issue264(array(1, 2, 3))); + $this->assertFalse($t->issue264([1, 2, 3])); } public function testIssue743() { $t = new NativeArray(); - - $expected = array(42 => array("str" => "ok")); - $this->assertSame($expected, $t->issue743a(array(42 => array()))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => null)))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => 42.7)))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => 42)))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => true)))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => "bad")))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => array())))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => array("hey"))))); - $this->assertSame($expected, $t->issue743a(array(42 => array("str" => new \stdClass())))); - - $expected = array("str" => array(42 => "ok")); - $this->assertSame($expected, $t->issue743b(array("str" => array()))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => null)))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => 42.7)))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => 42)))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => true)))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => "bad")))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => array())))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => array("hey"))))); - $this->assertSame($expected, $t->issue743b(array("str" => array(42 => new \stdClass())))); - - $expected = array("str" => array("hey" => "ok")); - $this->assertSame($expected, $t->issue743c(array("str" => array()))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => null)))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => 42.7)))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => 42)))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => true)))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => "bad")))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => array())))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => array("hey"))))); - $this->assertSame($expected, $t->issue743c(array("str" => array("hey" => new \stdClass())))); + $t->issue743a([42 => []]); + + $expected = [42 => ["str" => "ok"]]; + $this->assertSame($expected, $t->issue743a([42 => []])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => null]])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => 42.7]])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => 42]])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => true]])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => "bad"]])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => []]])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => ["hey"]]])); + $this->assertSame($expected, $t->issue743a([42 => ["str" => new \stdClass()]])); + + $expected = ["str" => [42 => "ok"]]; + $this->assertSame($expected, $t->issue743b(["str" => []])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => null]])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => 42.7]])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => 42]])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => true]])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => "bad"]])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => []]])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => ["hey"]]])); + $this->assertSame($expected, $t->issue743b(["str" => [42 => new \stdClass()]])); + + $expected = ["str" => ["hey" => "ok"]]; + $this->assertSame($expected, $t->issue743c(["str" => []])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => null]])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => 42.7]])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => 42]])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => true]])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => "bad"]])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => []]])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => ["hey"]]])); + $this->assertSame($expected, $t->issue743c(["str" => ["hey" => new \stdClass()]])); } public function testIssue709() diff --git a/unit-tests/Extension/RequiresTest.php b/unit-tests/Extension/RequiresTest.php index 95973cf7c9..6cee1f8a27 100644 --- a/unit-tests/Extension/RequiresTest.php +++ b/unit-tests/Extension/RequiresTest.php @@ -1,33 +1,42 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Extension; use Test\Requires; +use PHPUnit\Framework\TestCase; -class RequiresTest extends \PHPUnit_Framework_TestCase +class RequiresTest extends TestCase { public function testRequireExternal1() { $r = new Requires(); - $this->assertSame($r->requireExternal1(__DIR__ . '/php/require-me-1.php'), array(1, 2, 3)); - $this->assertTrue($r->requireExternal1(__DIR__ . '/php/require-me-2.php') && defined('REQUIRE_ME')); + + $this->assertSame( + [1, 2, 3], + $r->requireExternal1(__DIR__ . '/../fixtures/require-me-1.php') + ); + + $this->assertFalse(defined('REQUIRE_ME')); + $r->requireExternal1(__DIR__ . '/../fixtures/require-me-2.php'); + $this->assertTrue(defined('REQUIRE_ME')); } public function testRequireExternal3() { $r = new Requires(); - $output = $r->requireExternal3(__DIR__ . '/php/require-me-3.php'); - $this->assertSame("test", $output); + + $this->assertSame( + 'test', + $r->requireExternal3(__DIR__ . '/../fixtures/require-me-3.php') + ); } } diff --git a/unit-tests/Extension/fixtures/exit.php b/unit-tests/Extension/fixtures/exit.php deleted file mode 100644 index be3801e64e..0000000000 --- a/unit-tests/Extension/fixtures/exit.php +++ /dev/null @@ -1,12 +0,0 @@ -testExit(); diff --git a/unit-tests/Extension/fixtures/exit_int.php b/unit-tests/Extension/fixtures/exit_int.php deleted file mode 100644 index 6f6be82b80..0000000000 --- a/unit-tests/Extension/fixtures/exit_int.php +++ /dev/null @@ -1,16 +0,0 @@ -testExit($v); -} diff --git a/unit-tests/Extension/fixtures/exit_string.php b/unit-tests/Extension/fixtures/exit_string.php deleted file mode 100644 index 43adc70d38..0000000000 --- a/unit-tests/Extension/fixtures/exit_string.php +++ /dev/null @@ -1,15 +0,0 @@ -testExit($argv[1]); -} diff --git a/unit-tests/Extension/php/exists.php b/unit-tests/Extension/php/exists.php deleted file mode 100644 index b3d9bbc7f3..0000000000 --- a/unit-tests/Extension/php/exists.php +++ /dev/null @@ -1 +0,0 @@ -someVariable["test"] = "test"; -echo $this->someVariable["test"]; diff --git a/unit-tests/Zephir/Stubs/MethodDocBlockTest.php b/unit-tests/Zephir/Stubs/MethodDocBlockTest.php index 7cb3b83086..d828bdca90 100644 --- a/unit-tests/Zephir/Stubs/MethodDocBlockTest.php +++ b/unit-tests/Zephir/Stubs/MethodDocBlockTest.php @@ -6,8 +6,9 @@ use Zephir\ClassDefinition; use Zephir\StatementsBlock; use Zephir\AliasManager; +use PHPUnit\Framework\TestCase; -class MethodDocBlockTest extends \PHPUnit_Framework_TestCase +class MethodDocBlockTest extends TestCase { public function prepareMethod($params) { diff --git a/unit-tests/Zephir/Support/PhpUnitCommand.php b/unit-tests/Zephir/Support/PhpUnitCommand.php new file mode 100644 index 0000000000..f51bac1ecd --- /dev/null +++ b/unit-tests/Zephir/Support/PhpUnitCommand.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Zephir\Support; + +use PHPUnit\TextUI\Command; + +class PhpUnitCommand extends Command +{ + /** + * Start testing. + * + * @return int + */ + public static function start() + { + $exit = true; + + if (\getenv('PHPUNIT_DONT_EXIT')) { + $exit = false; + } elseif (defined('PHPUNIT_DONT_EXIT')) { + $exit = (bool) constant('PHPUNIT_DONT_EXIT'); + } + + return parent::main($exit); + } +} diff --git a/unit-tests/Zephir/Support/TestCase.php b/unit-tests/Zephir/Support/TestCase.php new file mode 100644 index 0000000000..293edb071e --- /dev/null +++ b/unit-tests/Zephir/Support/TestCase.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Zephir\Support; + +use PHPUnit\Framework\TestCase as BaseTestCase; + +abstract class TestCase extends BaseTestCase +{ + /** + * {@inheritdoc} + * + * @return string + */ + public function toString() + { + $className = get_class($this); + $className = explode('\\', $className); + $className = array_pop($className); + + $method = $this->getPrintableMethodName(); + + $buffer = sprintf('%s: %s', $className, $method); + + return $buffer . $this->getDataSetAsString(); + } + + protected function getPrintableMethodName() + { + $method = $this->getName(); + $method = preg_replace('#^(test|should)#', '', $method); + $parts = preg_split('/(?=[A-Z])/', $method); + $method = implode(' ', array_map(function ($part) { + return mb_strtolower($part); + }, $parts)); + + $method = ucfirst(trim($method)); + + return $method ?: 'Test'; + } +} diff --git a/unit-tests/Zephir/Support/compat.php b/unit-tests/Zephir/Support/compat.php new file mode 100644 index 0000000000..30dabe26bc --- /dev/null +++ b/unit-tests/Zephir/Support/compat.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ define('TESTS_PATH', dirname(__FILE__)); define('DATA_PATH', dirname(__FILE__) . '/Data'); -defined('ZEPHIRPATH') || define('ZEPHIRPATH', dirname(__DIR__) . DIRECTORY_SEPARATOR); +defined('ZEPHIRPATH') || define('ZEPHIRPATH', dirname(__DIR__)); if (!extension_loaded('phalcon')) { - include_once ZEPHIRPATH . 'prototypes/phalcon.php'; + include_once ZEPHIRPATH . '/prototypes/phalcon.php'; } if (!extension_loaded('test')) { diff --git a/unit-tests/ci/999-default.ini b/unit-tests/ci/999-default.ini new file mode 100644 index 0000000000..c48773c8f4 --- /dev/null +++ b/unit-tests/ci/999-default.ini @@ -0,0 +1,6 @@ +variables_order=EGPCS +enable_dl=true +opcache.enable=0 +opcache.enable_cli=0 +zend.assertions=1 +assert.exception=On diff --git a/unit-tests/ci/after-failure.sh b/unit-tests/ci/after-failure.sh new file mode 100755 index 0000000000..03b79b3151 --- /dev/null +++ b/unit-tests/ci/after-failure.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# +# This file is part of the Zephir. +# +# (c) Zephir Team +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. + +shopt -s nullglob + +$(phpenv which php) -v +$(phpenv which php) -m + +export LC_ALL=C + +for i in core core*; do + if [ -f "$i" -a "$(file "$i" | grep -o 'core file')" ]; then + gdb -q $(phpenv which php) "$i" < +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. + +if [ "${CI}" != "true" ]; then + echo "This script is designed to run inside a CI container only. Stop." + exit 1 +fi + +PROJECT_ROOT=$(readlink -enq "$(dirname $0)/../../") + +if [ "x${REPORT_COVERAGE}" = "x1" ]; then + output=${PROJECT_ROOT}/unit-tests/output/coverage.info + + lcov --no-checksum --directory ${PROJECT_ROOT}/ext --capture --compat-libtool --output-file ${output} + lcov \ + --remove ${output} "/usr*" \ + --remove ${output} "*/.phpenv/*" \ + --remove ${output} "${HOME}/build/include/*" \ + --compat-libtool \ + --output-file ${output} + + coveralls-lcov ${output} +fi diff --git a/unit-tests/ci/after_failure.sh b/unit-tests/ci/after_failure.sh deleted file mode 100755 index 01ed830a81..0000000000 --- a/unit-tests/ci/after_failure.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -shopt -s nullglob -export LC_ALL=C -for i in core*; do - if [ -f "$i" -a "$(file "$i" | grep -o 'core file')" ]; then - gdb -q $(phpenv which php) "$i" < +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. + +echo -e "Install a tool for writing fast and flexible scanners in C from regular expressions" + +if [ "${CI}" != "true" ]; then + echo "This script is designed to run inside a CI container only. Stop." + exit 1 +fi + +if [ -z ${RE2C_VERSION+x} ]; then + echo "The RE2C_VERSION is unset. Stop." + exit 1 +fi + +if [ "${RE2C_VERSION}" == "system" ]; then + echo "Use system re2c. Skip." + exit 0 +fi + +pkgname=re2c +source="https://github.com/skvadrik/${pkgname}/releases/download/${RE2C_VERSION}/${pkgname}-${RE2C_VERSION}.tar.gz" +downloaddir="${HOME}/.cache/${pkgname}/${pkgname}-${RE2C_VERSION}" +prefix="${HOME}/.local/opt/${pkgname}/${pkgname}-${RE2C_VERSION}" +bindir="${prefix}/bin" + +if [ ! -f "${bindir}/re2c" ]; then + if [ ! -d `dirname ${downloaddir}` ]; then + mkdir -p `dirname ${downloaddir}` + fi + + cd `dirname ${downloaddir}` + + if [ ! -f "${pkgname}-${RE2C_VERSION}.tar.gz" ]; then + curl -sSL "$source" -o "${pkgname}-${RE2C_VERSION}.tar.gz" + fi + + if [ ! -f "${pkgname}-${RE2C_VERSION}.tar.gz" ]; then + echo "Unable to locate ${pkgname}-${RE2C_VERSION}.tar.gz file. Stop." + exit 1 + fi + + if [ ! -d "${downloaddir}" ]; then + mkdir -p "${downloaddir}" + tar -zxf "${pkgname}-${RE2C_VERSION}.tar.gz" + fi + + if [ ! -d "${downloaddir}" ]; then + echo "Unable to locate re2c source. Stop." + exit 1 + fi + + if [ ! -d "${prefix}" ]; then + mkdir -p "${prefix}" + fi + + cd "${downloaddir}" + ./configure --prefix="${prefix}" + + make -j"$(getconf _NPROCESSORS_ONLN)" + make install +fi + +if [ ! -x "${bindir}/re2c" ]; then + echo "Unable to locate re2c executable. Stop." + exit 1 +fi + +mkdir -p ${HOME}/bin +ln -s "${bindir}/re2c" ${HOME}/bin/re2c + +re2c --version +exit 0 diff --git a/unit-tests/ci/install-test-ext.sh b/unit-tests/ci/install-test-ext.sh new file mode 100755 index 0000000000..023ee7c207 --- /dev/null +++ b/unit-tests/ci/install-test-ext.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# +# This file is part of the Zephir. +# +# (c) Zephir Team +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. + +# Exit the script if any statement returns a non-true return value +set -e + +# Ensure that this is being run inside a CI container +if [ "${CI}" != "true" ]; then + echo "This script is designed to run inside a CI container only. Exiting" + exit 1 +fi + +PROJECT_ROOT=$(readlink -enq "$(dirname $0)/../../") + +shopt -s nullglob + +pushd "${PROJECT_ROOT}/ext" +pushd "${PROJECT_ROOT}" + +$(phpenv which php) compiler.php help +$(phpenv which php) compiler.php clean +$(phpenv which php) compiler.php fullclean +$(phpenv which php) compiler.php generate ${DEFAULT_ZFLAGS} +$(phpenv which php) compiler.php stubs >/dev/null 2>&1 +$(phpenv which php) compiler.php api >/dev/null 2>&1 + +popd + +phpenv config-rm zephir-parser.ini || true + +$(phpenv which phpize) + +# However, the version of libtool that claims to no longer remove .gcno profiler information is libtool 2.2.6. +# The fix is probably in later libtool versions as well. +if [ -f /etc/gentoo-release ]; then + # Gentoo Linux + LIBTOOLIZE_BIN=$(command -v libtoolize 2>/dev/null) + aclocal && ${LIBTOOLIZE_BIN} --copy --force && autoheader && autoconf +elif [ "$(uname -s 2>/dev/null)" = "Darwin" ]; then + # macOS + LIBTOOLIZE_BIN=$(command -v glibtoolize 2>/dev/null) + aclocal && ${LIBTOOLIZE_BIN} --copy --force && autoheader && autoconf +else + # Linux + aclocal && libtoolize --copy --force && autoheader && autoconf +fi + +CFLAGS="${CFLAGS}" +LDFLAGS="${LDFLAGS}" + +if [ "${REPORT_COVERAGE}" = "1" ]; then + CFLAGS="--coverage -fprofile-arcs -ftest-coverage $CFLAGS" + LDFLAGS="--coverage ${LDFLAGS}" +fi + +./configure --with-php-config=$(phpenv which php-config) --enable-test CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" + +make -j"$(getconf _NPROCESSORS_ONLN)" + +if [ "x${REPORT_COVERAGE}" = "x1" ]; then + output=${PROJECT_ROOT}/unit-tests/output/coverage.info + + lcov --directory ${PROJECT_ROOT}/ext --zerocounters + lcov --directory ${PROJECT_ROOT}/ext --capture --compat-libtool --initial --output-file ${output} +fi + +popd + +exit $? diff --git a/unit-tests/ci/install_zephir_parser.sh b/unit-tests/ci/install-zephir-parser.sh old mode 100644 new mode 100755 similarity index 71% rename from unit-tests/ci/install_zephir_parser.sh rename to unit-tests/ci/install-zephir-parser.sh index c30d793911..6933e48679 --- a/unit-tests/ci/install_zephir_parser.sh +++ b/unit-tests/ci/install-zephir-parser.sh @@ -1,4 +1,11 @@ #!/usr/bin/env bash +# +# This file is part of the Zephir. +# +# (c) Zephir Team +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. # Exit the script if any statement returns a non-true return value set -e @@ -9,16 +16,11 @@ if [ "${CI}" != "true" ]; then exit 1 fi -required_vars=(ZEPHIR_PARSER_VERSION PHP_MAJOR PHP_MINOR) -missing_vars=() +export PHP_MAJOR="$(`phpenv which php` -r 'echo phpversion();' | cut -d '.' -f 1)" +export PHP_MINOR="$(`phpenv which php` -r 'echo phpversion();' | cut -d '.' -f 2)" -for i in "${required_vars[@]}"; do - test -n "${!i:+y}" || missing_vars+=("$i") -done - -if [ ${#missing_vars[@]} -ne 0 ]; then - echo "Variables aren't set: " >&2 - printf ' %q\n' "${missing_vars[@]}" >&2 +if [ -z ${ZEPHIR_PARSER_VERSION+x} ]; then + echo "The ZEPHIR_PARSER_VERSION is unset. Stop." exit 1 fi @@ -48,4 +50,4 @@ fi echo "[Zephir Parser]" > $(phpenv root)/versions/$(phpenv version-name)/etc/conf.d/zephir-parser.ini echo "extension=${LOCAL_LIBRARY}" >> $(phpenv root)/versions/$(phpenv version-name)/etc/conf.d/zephir-parser.ini -php --ri 'Zephir Parser' +$(phpenv which php) --ri 'Zephir Parser' diff --git a/unit-tests/ci/run-unit-tests.sh b/unit-tests/ci/run-unit-tests.sh new file mode 100755 index 0000000000..b43131b9e9 --- /dev/null +++ b/unit-tests/ci/run-unit-tests.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# +# This file is part of the Zephir. +# +# (c) Zephir Team +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. + +PROJECT_ROOT=$(readlink -enq "$(dirname $0)/../../") + +shopt -s nullglob + +pushd ${PROJECT_ROOT} + +export PHP_MAJOR="$(`phpenv which php` -r 'echo phpversion();' | cut -d '.' -f 1)" +export PHP_MINOR="$(`phpenv which php` -r 'echo phpversion();' | cut -d '.' -f 2)" +export PHPUNIT_DONT_EXIT=1 + +confing_file=${PROJECT_ROOT}/phpunit.xml.dist + +if [ "${PHP_MAJOR}.${PHP_MINOR}" = "7.3" ] || [ "${PHP_MAJOR}.${PHP_MINOR}" = "7.4" ]; then + export USE_ZEND_ALLOC=1 + confing_file=${PROJECT_ROOT}/phpunit-php-73.xml.dist +fi + +$(phpenv which php) -d extension=ext/modules/test.so unit-tests/phpunit -c ${confing_file} +status=$? + +popd + +exit ${status} diff --git a/unit-tests/ci/test.ini b/unit-tests/ci/test.ini deleted file mode 100644 index 3128f5c4bf..0000000000 --- a/unit-tests/ci/test.ini +++ /dev/null @@ -1 +0,0 @@ -extension=test.so diff --git a/unit-tests/fixtures/exists.php b/unit-tests/fixtures/exists.php new file mode 100644 index 0000000000..c2e4540837 --- /dev/null +++ b/unit-tests/fixtures/exists.php @@ -0,0 +1,10 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ diff --git a/unit-tests/fixtures/exit.php b/unit-tests/fixtures/exit.php new file mode 100644 index 0000000000..a0df138251 --- /dev/null +++ b/unit-tests/fixtures/exit.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Test\ExitDie; + +if (!extension_loaded('test')) { + if (ini_get('enable_dl') == '1') { + $prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' : ''; + dl($prefix . 'test.' . PHP_SHLIB_SUFFIX); + } +} + +if (!extension_loaded('test')) { + exit('"test" extension not loaded; cannot run tests without it'); +} + +$t = new ExitDie(); +$t->testExit(); diff --git a/unit-tests/fixtures/exit_int.php b/unit-tests/fixtures/exit_int.php new file mode 100644 index 0000000000..ee1b44d359 --- /dev/null +++ b/unit-tests/fixtures/exit_int.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Test\ExitDie; + +if (!extension_loaded('test')) { + if (ini_get('enable_dl') == '1') { + $prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' : ''; + dl($prefix . 'test.' . PHP_SHLIB_SUFFIX); + } +} + +if (!extension_loaded('test')) { + exit('"test" extension not loaded; cannot run tests without it'); +} + +$argv = $_SERVER['argv']; + +if (isset($argv[1])) { + $t = new ExitDie(); + $v = intval($argv[1]); + $t->testExit($v); +} diff --git a/unit-tests/fixtures/exit_string.php b/unit-tests/fixtures/exit_string.php new file mode 100644 index 0000000000..e8ab3a4672 --- /dev/null +++ b/unit-tests/fixtures/exit_string.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Test\ExitDie; + +if (!extension_loaded('test')) { + if (ini_get('enable_dl') == '1') { + $prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' : ''; + dl($prefix . 'test.' . PHP_SHLIB_SUFFIX); + } +} + +if (!extension_loaded('test')) { + exit('"test" extension not loaded; cannot run tests without it'); +} + +$argv = $_SERVER['argv']; +if (isset($argv[1])) { + $t = new ExitDie(); + $t->testExit($argv[1]); +} diff --git a/unit-tests/fixtures/require-me-1.php b/unit-tests/fixtures/require-me-1.php new file mode 100644 index 0000000000..5868c2a8a8 --- /dev/null +++ b/unit-tests/fixtures/require-me-1.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [1, 2, 3]; diff --git a/unit-tests/fixtures/require-me-2.php b/unit-tests/fixtures/require-me-2.php new file mode 100644 index 0000000000..926e0a70ac --- /dev/null +++ b/unit-tests/fixtures/require-me-2.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +define('REQUIRE_ME', 32); diff --git a/unit-tests/fixtures/require-me-3.php b/unit-tests/fixtures/require-me-3.php new file mode 100644 index 0000000000..151f923805 --- /dev/null +++ b/unit-tests/fixtures/require-me-3.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$this->someVariable["test"] = "test"; +echo $this->someVariable["test"]; diff --git a/unit-tests/microbench.php b/unit-tests/microbench.php index 47c73e3ebd..52a0fd7079 100644 --- a/unit-tests/microbench.php +++ b/unit-tests/microbench.php @@ -1,15 +1,13 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ require __DIR__ . '/../bootstrap.php'; diff --git a/unit-tests/output/.gitignore b/unit-tests/output/.gitignore index e69de29bb2..d6b7ef32c8 100644 --- a/unit-tests/output/.gitignore +++ b/unit-tests/output/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/unit-tests/phpunit b/unit-tests/phpunit index bf187b62f6..a47edc2bcc 100755 --- a/unit-tests/phpunit +++ b/unit-tests/phpunit @@ -2,31 +2,22 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'bootstrap.php'; +use Zephir\Support\PhpUnitCommand; -if (!class_exists('\PHPUnit\Framework\TestCase') and class_exists('PHPUnit_Framework_TestCase')) { - /** @noinspection PhpIgnoredClassAliasDeclaration */ - class_alias('PHPUnit_Framework_TestCase', '\PHPUnit\Framework\TestCase'); -} - -$exit = true; -if ($index = array_search('--not-exit', $_SERVER['argv'])) { - $exit = false; - unset($_SERVER['argv'][$index]); -} +require_once dirname(__DIR__) . '/bootstrap.php'; +require_once __DIR__ . '/Zephir/Support/compat.php'; -if (!class_exists('PHPUnit_TextUI_Command')) { - fwrite(STDERR, +if (!class_exists(PhpUnitCommand::class)) { + fwrite( + STDERR, 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL . ' composer install' . PHP_EOL . PHP_EOL . 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL @@ -35,7 +26,4 @@ if (!class_exists('PHPUnit_TextUI_Command')) { die(1); } -$res = PHPUnit_TextUI_Command::main($exit); -if ($res) { - exit($res); -} +PhpUnitCommand::start();