From 6d08c61164336b7732898162f897a7019c5d4183 Mon Sep 17 00:00:00 2001 From: Maciej Holyszko <14310995+falkenhawk@users.noreply.github.com> Date: Tue, 7 May 2019 15:26:25 +0200 Subject: [PATCH 1/8] Travis configuration for PHP 5.3-7.3 --- .travis.yml | 33 +++++++++++++-------------------- composer.json | 2 +- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c6bfe73a49..1aa7c8be631 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,22 @@ language: php -php: - - 5.3.3 - - 5.3 - - 5.4 - - 5.5 - - 5.6 - - hhvm +matrix: + include: + - php: 5.3 + dist: precise + - php: 5.4 + - php: 5.5 + - php: 5.6 + - php: 7.0 + - php: 7.1 + - php: 7.2 + - php: 7.3 env: - - INSTALL_PHP_INVOKER=0 - - INSTALL_PHP_INVOKER=1 + - INSTALL_PHP_INVOKER=0 + - INSTALL_PHP_INVOKER=1 before_script: - sh -c "if [ '$INSTALL_PHP_INVOKER' = '1' ]; then composer require --dev --prefer-source phpunit/php-invoker:\>=1.1.0,\<1.2.0; else composer install --dev --prefer-source; fi" script: ./phpunit.php --configuration ./build/travis-ci.xml - -matrix: - allow_failures: - - php: hhvm - -notifications: - email: false - irc: - channels: - - "irc.freenode.org#phpunit" - use_notice: true diff --git a/composer.json b/composer.json index c6077c8c2cc..63179487744 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "repositories": [ { "type": "pear", - "url": "http://pear.php.net" + "url": "https://pear.php.net" } ], "suggest": { From 2f70f140dbd1b0d76d3479430cec699f464ba08f Mon Sep 17 00:00:00 2001 From: Maciej Holyszko <14310995+falkenhawk@users.noreply.github.com> Date: Tue, 7 May 2019 17:12:22 +0200 Subject: [PATCH 2/8] Tests adjustments for php 5.6 + fixed php-timer dependency, which printed "Mb" for memory value + corrected signature of DomDocument::assertEquals method --- PHPUnit/Framework/Comparator/DOMDocument.php | 2 +- Tests/TextUI/fatal-isolation.phpt | 2 +- Tests/TextUI/fatal.phpt | 2 +- Tests/TextUI/log-json.phpt | 18 +++++++----------- composer.json | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/PHPUnit/Framework/Comparator/DOMDocument.php b/PHPUnit/Framework/Comparator/DOMDocument.php index 562b8fbcc22..8ffb21cf544 100644 --- a/PHPUnit/Framework/Comparator/DOMDocument.php +++ b/PHPUnit/Framework/Comparator/DOMDocument.php @@ -83,7 +83,7 @@ public function accepts($expected, $actual) * fails. Contains information about the * specific errors that lead to the failure. */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) + public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE, array &$processed = array()) { if ($expected->C14N() !== $actual->C14N()) { throw new PHPUnit_Framework_ComparisonFailure( diff --git a/Tests/TextUI/fatal-isolation.phpt b/Tests/TextUI/fatal-isolation.phpt index 5965c079c8c..09ebf497862 100644 --- a/Tests/TextUI/fatal-isolation.phpt +++ b/Tests/TextUI/fatal-isolation.phpt @@ -21,7 +21,7 @@ Time: %s, Memory: %sMb There was 1 error: 1) FatalTest::testFatalError -PHPUnit_Framework_Exception: %s error: Call to undefined function non_existing_function() in %s +%s FAILURES! diff --git a/Tests/TextUI/fatal.phpt b/Tests/TextUI/fatal.phpt index da1955701bf..80015ddeafb 100644 --- a/Tests/TextUI/fatal.phpt +++ b/Tests/TextUI/fatal.phpt @@ -14,4 +14,4 @@ PHPUnit_TextUI_Command::main(); PHPUnit %s by Sebastian Bergmann. -Fatal error: Call to undefined function non_existing_function() in %s +%s diff --git a/Tests/TextUI/log-json.phpt b/Tests/TextUI/log-json.phpt index 4e68793b855..2dfb050b6f2 100644 --- a/Tests/TextUI/log-json.phpt +++ b/Tests/TextUI/log-json.phpt @@ -2,8 +2,10 @@ phpunit --log-json php://stdout BankAccountTest ../_files/BankAccountTest.php --SKIPIF-- = 5.4"; +if (!defined('JSON_PRETTY_PRINT')) { + print 'skip: JSON_PRETTY_PRINT is required'; +} elseif (json_encode(array(), JSON_PRETTY_PRINT) != '[]') { + print 'skip: Does not have PHP #66021 (Blank line inside empty JSON array/object)'; } --FILE-- Date: Tue, 7 May 2019 18:59:51 +0200 Subject: [PATCH 3/8] php 7.3 compatibility fixes --- PHPUnit/Framework/Assert.php | 6 +++--- PHPUnit/TextUI/Command.php | 4 ++-- PHPUnit/Util/Test.php | 2 +- Tests/Framework/TestCaseTest.php | 4 ++-- Tests/Framework/TestListenerTest.php | 4 ++-- Tests/TextUI/log-json.phpt | 6 +++--- Tests/_files/{Error.php => TestError.php} | 2 +- composer.json | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) rename Tests/_files/{Error.php => TestError.php} (62%) diff --git a/PHPUnit/Framework/Assert.php b/PHPUnit/Framework/Assert.php index 67f427f0185..b10af95ea1f 100644 --- a/PHPUnit/Framework/Assert.php +++ b/PHPUnit/Framework/Assert.php @@ -1918,7 +1918,7 @@ public static function assertSelectEquals($selector, $content, $count, $actual, // assert any elements exist if true, assert no elements exist if false else if (is_bool($count)) { - $any = count($tags) > 0 && $tags[0] instanceof DOMNode; + $any = $tags && count($tags) > 0 && $tags[0] instanceof DOMNode; if ($count) { self::assertTrue($any, $message); @@ -2094,7 +2094,7 @@ public static function assertTag($matcher, $actual, $message = '', $isHtml = TRU { $dom = PHPUnit_Util_XML::load($actual, $isHtml); $tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml); - $matched = count($tags) > 0 && $tags[0] instanceof DOMNode; + $matched = $tags && count($tags) > 0 && $tags[0] instanceof DOMNode; self::assertTrue($matched, $message); } @@ -2117,7 +2117,7 @@ public static function assertNotTag($matcher, $actual, $message = '', $isHtml = { $dom = PHPUnit_Util_XML::load($actual, $isHtml); $tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml); - $matched = count($tags) > 0 && $tags[0] instanceof DOMNode; + $matched = $tags && count($tags) > 0 && $tags[0] instanceof DOMNode; self::assertFalse($matched, $message); } diff --git a/PHPUnit/TextUI/Command.php b/PHPUnit/TextUI/Command.php index 6cf86701473..799b181af0c 100644 --- a/PHPUnit/TextUI/Command.php +++ b/PHPUnit/TextUI/Command.php @@ -274,7 +274,7 @@ protected function handleArguments(array $argv) 'tokenizer', 'No code coverage will be generated.' ); - continue; + break; } if (!extension_loaded('xdebug')) { @@ -282,7 +282,7 @@ protected function handleArguments(array $argv) 'Xdebug', 'No code coverage will be generated.' ); - continue; + break; } switch ($option[0]) { diff --git a/PHPUnit/Util/Test.php b/PHPUnit/Util/Test.php index d2639df0b2e..12d02a251be 100644 --- a/PHPUnit/Util/Test.php +++ b/PHPUnit/Util/Test.php @@ -210,7 +210,7 @@ public static function getExpectedException($className, $methodName) */ protected static function _parseAnnotationContent($message) { - if (strpos($message, '::') !== FALSE && count(explode('::', $message) == 2)) { + if (strpos($message, '::') !== FALSE && count(explode('::', $message)) == 2) { if (defined($message)) { $message = constant($message); } diff --git a/Tests/Framework/TestCaseTest.php b/Tests/Framework/TestCaseTest.php index 417d57cb18e..3485ffcd526 100644 --- a/Tests/Framework/TestCaseTest.php +++ b/Tests/Framework/TestCaseTest.php @@ -42,7 +42,7 @@ * @since File available since Release 2.0.0 */ -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Error.php'; +require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'TestError.php'; require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInAssertPostConditionsTest.php'; require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInAssertPreConditionsTest.php'; require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInSetUpTest.php'; @@ -113,7 +113,7 @@ public function testFailure() public function testError() { - $test = new Error; + $test = new TestError; $result = $test->run(); $this->assertEquals(1, $result->errorCount()); diff --git a/Tests/Framework/TestListenerTest.php b/Tests/Framework/TestListenerTest.php index df2c1ead0c0..d89606c49c2 100644 --- a/Tests/Framework/TestListenerTest.php +++ b/Tests/Framework/TestListenerTest.php @@ -42,7 +42,7 @@ * @since File available since Release 2.0.0 */ -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Error.php'; +require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'TestError.php'; require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Failure.php'; require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Success.php'; @@ -118,7 +118,7 @@ protected function setUp() public function testError() { - $test = new Error; + $test = new TestError; $test->run($this->result); $this->assertEquals(1, $this->errorCount); diff --git a/Tests/TextUI/log-json.phpt b/Tests/TextUI/log-json.phpt index 2dfb050b6f2..cb6ff43fb43 100644 --- a/Tests/TextUI/log-json.phpt +++ b/Tests/TextUI/log-json.phpt @@ -36,7 +36,7 @@ PHPUnit %s by Sebastian Bergmann. "suite": "BankAccountTest", "test": "BankAccountTest::testBalanceIsInitiallyZero", "status": "pass", - "time": %f, + "time": %s, "trace": [], "message": "", "output": "" @@ -49,7 +49,7 @@ PHPUnit %s by Sebastian Bergmann. "suite": "BankAccountTest", "test": "BankAccountTest::testBalanceCannotBecomeNegative", "status": "pass", - "time": %f, + "time": %s, "trace": [], "message": "", "output": "" @@ -62,7 +62,7 @@ PHPUnit %s by Sebastian Bergmann. "suite": "BankAccountTest", "test": "BankAccountTest::testBalanceCannotBecomeNegative2", "status": "pass", - "time": %f, + "time": %s, "trace": [], "message": "", "output": "" diff --git a/Tests/_files/Error.php b/Tests/_files/TestError.php similarity index 62% rename from Tests/_files/Error.php rename to Tests/_files/TestError.php index 9417ba657ba..6f61b8ed6fa 100644 --- a/Tests/_files/Error.php +++ b/Tests/_files/TestError.php @@ -1,5 +1,5 @@ Date: Wed, 8 May 2019 11:40:12 +0200 Subject: [PATCH 4/8] Backported https://github.com/sebastianbergmann/phpunit/pull/773 - to avoid looping/memory leaks/segfaults on PHP 7.x - Alter PHPUnit_Util_Type::recursiveExport() to handle repeated and recursive data structures more gracefully (and with less memory usage). --- PHPUnit/Autoload.php | 1 + PHPUnit/Util/Type.php | 94 +++++++------- PHPUnit/Util/Type/ExportContext.php | 189 ++++++++++++++++++++++++++++ Tests/Framework/ConstraintTest.php | 34 ++--- Tests/Util/TypeTest.php | 27 ++-- 5 files changed, 265 insertions(+), 80 deletions(-) create mode 100644 PHPUnit/Util/Type/ExportContext.php diff --git a/PHPUnit/Autoload.php b/PHPUnit/Autoload.php index 16e3184b6ad..f3b9d051671 100644 --- a/PHPUnit/Autoload.php +++ b/PHPUnit/Autoload.php @@ -193,6 +193,7 @@ function ($class) 'phpunit_util_testdox_resultprinter_text' => '/Util/TestDox/ResultPrinter/Text.php', 'phpunit_util_testsuiteiterator' => '/Util/TestSuiteIterator.php', 'phpunit_util_type' => '/Util/Type.php', + 'phpunit_util_type_exportcontext' => '/Util/Type/ExportContext.php', 'phpunit_util_xml' => '/Util/XML.php' ); diff --git a/PHPUnit/Util/Type.php b/PHPUnit/Util/Type.php index 10f0e81dc21..de7a52048fb 100644 --- a/PHPUnit/Util/Type.php +++ b/PHPUnit/Util/Type.php @@ -105,13 +105,15 @@ public static function export($value, $indentation = 0) * * @param mixed $value The value to export * @param integer $indentation The indentation level of the 2nd+ line - * @param array $processedObjects Contains all objects that were already - * rendered + * @param PHPUnit_Util_Type_ExportContext $processed Contains all objects + * and arrays that have + * previously been + * rendered * @return string * @since Method available since Release 3.6.0 * @see PHPUnit_Util_Type::export */ - protected static function recursiveExport($value, $indentation, &$processedObjects = array()) + protected static function recursiveExport(&$value, $indentation, $processed = null) { if ($value === NULL) { return 'null'; @@ -125,6 +127,10 @@ protected static function recursiveExport($value, $indentation, &$processedObjec return 'false'; } + if (is_float($value) && floatval(intval($value)) === $value) { + return "$value.0"; + } + if (is_string($value)) { // Match for most non printable chars somewhat taking multibyte chars into account if (preg_match('/[^\x09-\x0d\x20-\xff]/', $value)) { @@ -136,71 +142,57 @@ protected static function recursiveExport($value, $indentation, &$processedObjec "'"; } - $origValue = $value; - - if (is_object($value)) { - if (in_array($value, $processedObjects, TRUE)) { - return sprintf( - '%s Object (*RECURSION*)', - - get_class($value) - ); - } - - $processedObjects[] = $value; + $whitespace = str_repeat(' ', 4 * $indentation); - // Convert object to array - $value = self::toArray($value); + if (!$processed) { + $processed = new PHPUnit_Util_Type_ExportContext; } if (is_array($value)) { - $whitespace = str_repeat(' ', $indentation); - - // There seems to be no other way to check arrays for recursion - // http://www.php.net/manual/en/language.types.array.php#73936 - preg_match_all('/\n \[(\w+)\] => Array\s+\*RECURSION\*/', print_r($value, TRUE), $matches); - $recursiveKeys = array_unique($matches[1]); - - // Convert to valid array keys - // Numeric integer strings are automatically converted to integers - // by PHP - foreach ($recursiveKeys as $key => $recursiveKey) { - if ((string)(integer)$recursiveKey === $recursiveKey) { - $recursiveKeys[$key] = (integer)$recursiveKey; - } + if (($key = $processed->contains($value)) !== false) { + return "Array &$key"; } - $content = ''; - - foreach ($value as $key => $val) { - if (in_array($key, $recursiveKeys, TRUE)) { - $val = 'Array (*RECURSION*)'; - } + $key = $processed->add($value); + if (count($value) > 0) { + $output = "Array &$key (\n"; - else { - $val = self::recursiveExport($val, $indentation+1, $processedObjects); + foreach ($value as $k => $v) { + $k = self::export($k); + $output .= "$whitespace $k => ".self::recursiveExport($v, $indentation + 1, $processed)."\n"; } - $content .= $whitespace . ' ' . self::export($key) . ' => ' . $val . "\n"; + return "$output$whitespace)"; + } else { + return "Array &$key ()"; } + } - if (strlen($content) > 0) { - $content = "\n" . $content . $whitespace; + if (is_object($value)) { + $class = get_class($value); + + if ($hash = $processed->contains($value)) { + return "$class Object &$hash"; } - return sprintf( - "%s (%s)", + $hash = $processed->add($value); + $array = self::toArray($value); + if (count($array) > 0) { + $output = "$class Object &$hash (\n"; - is_object($origValue) ? get_class($origValue) . ' Object' : 'Array', - $content - ); - } + foreach ($array as $k => $v) { + $k = self::export($k); + $output .= "$whitespace $k => ".self::recursiveExport($v, $indentation + 1, $processed)."\n"; + } + + return "$output$whitespace)"; + } else { + return "$class Object &$hash ()"; + } - if (is_double($value) && (double)(integer)$value === $value) { - return $value . '.0'; } - return (string)$value; + return var_export($value, true); } /** diff --git a/PHPUnit/Util/Type/ExportContext.php b/PHPUnit/Util/Type/ExportContext.php new file mode 100644 index 00000000000..5bdca020c89 --- /dev/null +++ b/PHPUnit/Util/Type/ExportContext.php @@ -0,0 +1,189 @@ +. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Sebastian Bergmann nor the names of his + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * @package PHPUnit + * @subpackage Util + * @author Adam Harvey + * @copyright 2001-2012 Sebastian Bergmann + * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License + * @link http://www.phpunit.de/ + * @since File available since Release 3.9.0 + */ + +/** + * A context containing previously rendered arrays and objects when recursively + * exporting a value. + * + * @package PHPUnit + * @subpackage Util + * @author Adam Harvey + * @copyright 2001-2012 Sebastian Bergmann + * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License + * @link http://www.phpunit.de/ + * @since Class available since Release 3.9.0 + */ +class PHPUnit_Util_Type_ExportContext { + /** + * Previously seen arrays. + * + * @var array[] $arrays + */ + protected $arrays; + + /** + * Previously seen objects. + * + * @var SplObjectStorage $objects + */ + protected $objects; + + /** Initialises the context. */ + public function __construct() + { + $this->arrays = array(); + $this->objects = new SplObjectStorage; + } + + /** + * Adds a value to the export context. + * + * @param mixed $value The value to add. + * @return mixed The ID of the stored value, either as a string or integer. + * @throws PHPUnit_Framework_Exception Thrown if $value is not an array or + * object. + */ + public function add(&$value) + { + if (is_array($value)) { + return $this->addArray($value); + } elseif (is_object($value)) { + return $this->addObject($value); + } + + throw new PHPUnit_Framework_Exception('Only arrays and objects are supported'); + } + + /** + * Checks if the given value exists within the context. + * + * @param mixed $value The value to check. + * @return mixed The string or integer ID of the stored value if it has + * already been seen, or boolean false if the value is not + * stored. + * @throws PHPUnit_Framework_Exception Thrown if $value is not an array or + * object. + */ + public function contains(&$value) + { + if (is_array($value)) { + return $this->containsArray($value); + } elseif (is_object($value)) { + return $this->containsObject($value); + } + + throw new PHPUnit_Framework_Exception('Only arrays and objects are supported'); + } + + /** + * Stores an array within the context. + * + * @param array $value The value to store. + * @return integer The internal ID of the array. + */ + protected function addArray(array &$value) + { + if (($key = $this->containsArray($value)) !== false) { + return $key; + } + + $this->arrays[] = &$value; + return count($this->arrays) - 1; + } + + /** + * Stores an object within the context. + * + * @param object $value + * @return string The ID of the object. + */ + protected function addObject($value) + { + if (!$this->objects->contains($value)) { + $this->objects->attach($value); + } + + return spl_object_hash($value); + } + + /** + * Checks if the given array exists within the context. + * + * @param array $value The array to check. + * @return mixed The integer ID of the array if it exists, or boolean false + * otherwise. + */ + protected function containsArray(array &$value) + { + $keys = array_keys($this->arrays, $value, true); + $gen = '_PHPUnit_Test_Key_'.hash('sha512', microtime(true)); + foreach ($keys as $key) { + $this->arrays[$key][$gen] = $gen; + if (isset($value[$gen]) && $value[$gen] === $gen) { + unset($this->arrays[$key][$gen]); + return $key; + } + unset($this->arrays[$key][$gen]); + } + + return false; + } + + /** + * Checks if the given object exists within the context. + * + * @param object $value The object to check. + * @return mixed The string ID of the object if it exists, or boolean false + * otherwise. + */ + protected function containsObject($value) + { + if ($this->objects->contains($value)) { + return spl_object_hash($value); + } + + return false; + } +} diff --git a/Tests/Framework/ConstraintTest.php b/Tests/Framework/ConstraintTest.php index 40813e32cc5..4d4ec230105 100644 --- a/Tests/Framework/ConstraintTest.php +++ b/Tests/Framework/ConstraintTest.php @@ -737,6 +737,8 @@ public function isEqualProvider() $storage1->attach($b); $storage2 = new SplObjectStorage; $storage2->attach($b); + $storage1hash = spl_object_hash($storage1); + $storage2hash = spl_object_hash($storage2); $dom1 = new DOMDocument; $dom1->preserveWhiteSpace = FALSE; @@ -892,17 +894,17 @@ public function isEqualProvider() --- Expected +++ Actual @@ @@ - SplObjectStorage Object ( -- '$ahash' => Array ( -- 'obj' => stdClass Object ( +-SplObjectStorage Object &$storage1hash ( +- '$ahash' => Array &0 ( +- 'obj' => stdClass Object &$ahash ( - 'foo' => 'bar' - ) -- 'inf' => null -- ) - '$bhash' => Array ( - 'obj' => stdClass Object () ++SplObjectStorage Object &$storage2hash ( ++ '$bhash' => Array &0 ( ++ 'obj' => stdClass Object &$bhash () 'inf' => null ) +- '$bhash' => Array &0 ) EOF @@ -1387,8 +1389,8 @@ public function testConstraintIsType() } catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<assertStringMatchesFormat(<<assertEquals(<<assertStringMatchesFormat(<<assertEquals("contains stdClass Object ()", $constraint->toString()); + $this->assertStringMatchesFormat("contains stdClass Object &%s ()", $constraint->toString()); $storage = new SplObjectStorage; $this->assertFalse($constraint->evaluate($storage, '', TRUE)); @@ -3206,9 +3208,9 @@ public function testConstraintSplObjectStorageContains() } catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( + $this->assertStringMatchesFormat( <<assertEquals( + $this->assertStringMatchesFormat( << null 'boolean' => true 'integer' => 1 @@ -146,21 +147,21 @@ public function exportProvider() very long text' - 'object' => stdClass Object ( + 'object' => stdClass Object &%x ( 'foo' => 'bar' ) - 'objectagain' => stdClass Object (*RECURSION*) - 'array' => Array ( + 'objectagain' => stdClass Object &%x + 'array' => Array &%d ( 'foo' => 'bar' ) - 'self' => stdClass Object (*RECURSION*) + 'self' => stdClass Object &%x ) EOF ), - array(array(), 'Array ()'), + array(array(), 'Array &%d ()'), array($array, << 0 'null' => null 'boolean' => true @@ -178,14 +179,14 @@ public function exportProvider() very long text' - 'object' => stdClass Object ( + 'object' => stdClass Object &%x ( 'foo' => 'bar' ) - 'objectagain' => stdClass Object (*RECURSION*) - 'array' => Array ( + 'objectagain' => stdClass Object &%x + 'array' => Array &%d ( 'foo' => 'bar' ) - 'self' => Array (*RECURSION*) + 'self' => Array &%d ) EOF ), @@ -213,7 +214,7 @@ public function exportProvider() */ public function testExport($value, $expected) { - $this->assertSame($expected, self::trimnl(PHPUnit_Util_Type::export($value))); + $this->assertStringMatchesFormat($expected, self::trimnl(PHPUnit_Util_Type::export($value))); } public function shortenedExportProvider() From 6965274de5f19e77108d5e474301fa1ab3855603 Mon Sep 17 00:00:00 2001 From: Maciej Holyszko <14310995+falkenhawk@users.noreply.github.com> Date: Wed, 8 May 2019 12:11:35 +0200 Subject: [PATCH 5/8] Backported https://github.com/sebastianbergmann/phpunit/pull/2536 - refactored Getopt + tests - each() is deprecated since php 7.2 --- PHPUnit/Util/Getopt.php | 70 ++++++------- Tests/Util/GetoptTest.php | 204 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+), 34 deletions(-) create mode 100644 Tests/Util/GetoptTest.php diff --git a/PHPUnit/Util/Getopt.php b/PHPUnit/Util/Getopt.php index 41ec26c02d3..45fb7d80410 100644 --- a/PHPUnit/Util/Getopt.php +++ b/PHPUnit/Util/Getopt.php @@ -77,7 +77,9 @@ public static function getopt(array $args, $short_options, $long_options = NULL) reset($args); array_map('trim', $args); - while (list($i, $arg) = each($args)) { + while (false !== $arg = current($args)) { + $i = key($args); + next($args); if ($arg == '') { continue; } @@ -88,20 +90,23 @@ public static function getopt(array $args, $short_options, $long_options = NULL) } if ($arg[0] != '-' || - (strlen($arg) > 1 && $arg[1] == '-' && !$long_options)) { - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } - - elseif (strlen($arg) > 1 && $arg[1] == '-') { + (strlen($arg) > 1 && $arg[1] == '-' && !$long_options) + ) { + $non_opts[] = $args[$i]; + continue; + } elseif (strlen($arg) > 1 && $arg[1] == '-') { self::parseLongOption( - substr($arg, 2), $long_options, $opts, $args + substr($arg, 2), + $long_options, + $opts, + $args ); - } - - else { + } else { self::parseShortOption( - substr($arg, 1), $short_options, $opts, $args + substr($arg, 1), + $short_options, + $opts, + $args ); } } @@ -118,32 +123,25 @@ protected static function parseShortOption($arg, $short_options, &$opts, &$args) $opt_arg = NULL; if (($spec = strstr($short_options, $opt)) === FALSE || - $arg[$i] == ':') { + $arg[$i] == ':' + ) { throw new PHPUnit_Framework_Exception( "unrecognized option -- $opt" ); } if (strlen($spec) > 1 && $spec[1] == ':') { - if (strlen($spec) > 2 && $spec[2] == ':') { - if ($i + 1 < $argLen) { - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } - } else { - if ($i + 1 < $argLen) { - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } - - else if (list(, $opt_arg) = each($args)) { - } - - else { + if ($i + 1 < $argLen) { + $opts[] = array($opt, substr($arg, $i + 1)); + break; + } + if (!(strlen($spec) > 2 && $spec[2] == ':')) { + if (false === $opt_arg = current($args)) { throw new PHPUnit_Framework_Exception( "option requires an argument -- $opt" ); } + next($args); } } @@ -183,11 +181,13 @@ protected static function parseLongOption($arg, $long_options, &$opts, &$args) if (substr($long_opt, -1) == '=') { if (substr($long_opt, -2) != '==') { - if (!strlen($opt_arg) && - !(list(, $opt_arg) = each($args))) { - throw new PHPUnit_Framework_Exception( - "option --$opt requires an argument" - ); + if (!strlen($opt_arg)) { + if (false === $opt_arg = current($args)) { + throw new PHPUnit_Framework_Exception( + "option --$opt requires an argument" + ); + } + next($args); } } } @@ -198,7 +198,9 @@ protected static function parseLongOption($arg, $long_options, &$opts, &$args) ); } - $opts[] = array('--' . $opt, $opt_arg); + $full_option = '--' . preg_replace('/={1,2}$/', '', $long_opt); + $opts[] = array($full_option, $opt_arg); + return; } diff --git a/Tests/Util/GetoptTest.php b/Tests/Util/GetoptTest.php new file mode 100644 index 00000000000..6eee83406ce --- /dev/null +++ b/Tests/Util/GetoptTest.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Util_GetoptTest extends PHPUnit_Framework_TestCase +{ + public function testItIncludeTheLongOptionsAfterTheArgument() + { + $args = array( + 'command', + 'myArgument', + '--colors', + ); + $actual = PHPUnit_Util_Getopt::getopt($args, '', array('colors==')); + + $expected = array( + array( + array( + '--colors', + null, + ), + ), + array( + 'myArgument', + ), + ); + + $this->assertEquals($expected, $actual); + } + + public function testItIncludeTheShortOptionsAfterTheArgument() + { + $args = array( + 'command', + 'myArgument', + '-v', + ); + $actual = PHPUnit_Util_Getopt::getopt($args, 'v'); + + $expected = array( + array( + array( + 'v', + null, + ), + ), + array( + 'myArgument', + ), + ); + + $this->assertEquals($expected, $actual); + } + + public function testShortOptionUnrecognizedException() + { + $args = array( + 'command', + 'myArgument', + '-v', + ); + + $this->setExpectedException('PHPUnit_Framework_Exception', 'unrecognized option -- v'); + + PHPUnit_Util_Getopt::getopt($args, ''); + } + + public function testShortOptionRequiresAnArgumentException() + { + $args = array( + 'command', + 'myArgument', + '-f', + ); + + $this->setExpectedException('PHPUnit_Framework_Exception', 'option requires an argument -- f'); + + PHPUnit_Util_Getopt::getopt($args, 'f:'); + } + + public function testShortOptionHandleAnOptionalValue() + { + $args = array( + 'command', + 'myArgument', + '-f', + ); + $actual = PHPUnit_Util_Getopt::getopt($args, 'f::'); + $expected = array( + array( + array( + 'f', + null, + ), + ), + array( + 'myArgument', + ), + ); + $this->assertEquals($expected, $actual); + } + + public function testLongOptionIsAmbiguousException() + { + $args = array( + 'command', + '--col', + ); + + $this->setExpectedException('PHPUnit_Framework_Exception', 'option --col is ambiguous'); + + PHPUnit_Util_Getopt::getopt($args, '', array('columns', 'colors')); + } + + public function testLongOptionUnrecognizedException() + { + // the exception 'unrecognized option --option' is not thrown + // if the there are not defined extended options + $args = array( + 'command', + '--foo', + ); + + $this->setExpectedException('PHPUnit_Framework_Exception', 'unrecognized option --foo'); + + PHPUnit_Util_Getopt::getopt($args, '', array('colors')); + } + + public function testLongOptionRequiresAnArgumentException() + { + $args = array( + 'command', + '--foo', + ); + + $this->setExpectedException('PHPUnit_Framework_Exception', 'option --foo requires an argument'); + + PHPUnit_Util_Getopt::getopt($args, '', array('foo=')); + } + + public function testLongOptionDoesNotAllowAnArgumentException() + { + $args = array( + 'command', + '--foo=bar', + ); + + $this->setExpectedException('PHPUnit_Framework_Exception', "option --foo doesn't allow an argument"); + + PHPUnit_Util_Getopt::getopt($args, '', array('foo')); + } + + public function testItHandlesLongParametesWithValues() + { + $command = 'command parameter-0 --exec parameter-1 --conf config.xml --optn parameter-2 --optn=content-of-o parameter-n'; + $args = explode(' ', $command); + unset($args[0]); + $expected = array( + array( + array('--exec', null), + array('--conf', 'config.xml'), + array('--optn', null), + array('--optn', 'content-of-o'), + ), + array( + 'parameter-0', + 'parameter-1', + 'parameter-2', + 'parameter-n', + ), + ); + $actual = PHPUnit_Util_Getopt::getopt($args, '', array('exec', 'conf=', 'optn==')); + $this->assertEquals($expected, $actual); + } + + public function testItHandlesShortParametesWithValues() + { + $command = 'command parameter-0 -x parameter-1 -c config.xml -o parameter-2 -ocontent-of-o parameter-n'; + $args = explode(' ', $command); + unset($args[0]); + $expected = array( + array( + array('x', null), + array('c', 'config.xml'), + array('o', null), + array('o', 'content-of-o'), + ), + array( + 'parameter-0', + 'parameter-1', + 'parameter-2', + 'parameter-n', + ), + ); + $actual = PHPUnit_Util_Getopt::getopt($args, 'xc:o::'); + $this->assertEquals($expected, $actual); + } +} From e1fd4d0490c0289c621a0b2d5ca591b83265543b Mon Sep 17 00:00:00 2001 From: Maciej Holyszko <14310995+falkenhawk@users.noreply.github.com> Date: Wed, 8 May 2019 12:19:16 +0200 Subject: [PATCH 6/8] Backported https://github.com/sebastianbergmann/phpunit/commit/c1fe4b7a93310bea8c25bf02ebb501310b2f9726 - fixes https://github.com/sebastianbergmann/phpunit/issues/1052 (precision errors on php 5.3-7.0) --- Tests/bootstrap.php | 5 +++++ build/travis-ci.xml | 1 + phpunit.xml.dist | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 Tests/bootstrap.php diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php new file mode 100644 index 00000000000..9a08cf0ba92 --- /dev/null +++ b/Tests/bootstrap.php @@ -0,0 +1,5 @@ + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index ee1d8f5cf85..4db0b8802bb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ From 8c9f8aa708053e9f0a893c71c43d1b357a151871 Mon Sep 17 00:00:00 2001 From: Maciej Holyszko <14310995+falkenhawk@users.noreply.github.com> Date: Wed, 8 May 2019 12:31:53 +0200 Subject: [PATCH 7/8] Adjusted travis config --- .travis.yml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1aa7c8be631..6150f023103 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,25 @@ language: php +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - 7.3 + +env: + - INSTALL_PHP_INVOKER=0 + - INSTALL_PHP_INVOKER=1 matrix: include: - php: 5.3 dist: precise - - php: 5.4 - - php: 5.5 - - php: 5.6 - - php: 7.0 - - php: 7.1 - - php: 7.2 - - php: 7.3 - -env: - - INSTALL_PHP_INVOKER=0 - - INSTALL_PHP_INVOKER=1 + env: INSTALL_PHP_INVOKER=0 + - php: 5.3 + dist: precise + env: INSTALL_PHP_INVOKER=1 before_script: - sh -c "if [ '$INSTALL_PHP_INVOKER' = '1' ]; then composer require --dev --prefer-source phpunit/php-invoker:\>=1.1.0,\<1.2.0; else composer install --dev --prefer-source; fi" From 17888c9e6720a56fefa6bc76a5fd32086ca033f1 Mon Sep 17 00:00:00 2001 From: Maciej Holyszko <14310995+falkenhawk@users.noreply.github.com> Date: Wed, 8 May 2019 13:15:45 +0200 Subject: [PATCH 8/8] 3.7.38-1 compat version for php 5.3-7.3 --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 09e10795bd5..9eb0199b6fd 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,8 @@ { - "name": "phpunit/phpunit", + "name": "zf1s/phpunit", + "replace": { + "phpunit/phpunit": "^3.7.38" + }, "description": "The PHP Unit Testing framework.", "type": "library", "keywords": [