diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 70717843640..b174a541811 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,6 +26,8 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" + - "8.5" php_invoker: [true, false] coverage: [false] experimental: [false] @@ -40,7 +42,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 diff --git a/PHPUnit/Extensions/PhptTestCase.php b/PHPUnit/Extensions/PhptTestCase.php index ccbe8821228..ddd2eddb112 100644 --- a/PHPUnit/Extensions/PhptTestCase.php +++ b/PHPUnit/Extensions/PhptTestCase.php @@ -117,8 +117,12 @@ public function count() * @param array $options * @return PHPUnit_Framework_TestResult */ - public function run(PHPUnit_Framework_TestResult $result = NULL, array $options = array()) + public function run($result = NULL, array $options = array()) { + if ($result !== NULL && !$result instanceof PHPUnit_Framework_TestResult) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'PHPUnit_Framework_TestResult'); + } + if (!class_exists('PEAR_RunTest', FALSE)) { $result->addFailure($this, new PHPUnit_Framework_SkippedTestError('PEAR_RunTest not available'), 0); return $result; diff --git a/PHPUnit/Extensions/RepeatedTest.php b/PHPUnit/Extensions/RepeatedTest.php index ea6dcc5415e..06d35c94c91 100644 --- a/PHPUnit/Extensions/RepeatedTest.php +++ b/PHPUnit/Extensions/RepeatedTest.php @@ -129,8 +129,12 @@ public function count() * @return PHPUnit_Framework_TestResult * @throws PHPUnit_Framework_Exception */ - public function run(PHPUnit_Framework_TestResult $result = NULL) + public function run($result = NULL) { + if ($result !== NULL && !$result instanceof PHPUnit_Framework_TestResult) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'PHPUnit_Framework_TestResult'); + } + if ($result === NULL) { $result = $this->createResult(); } diff --git a/PHPUnit/Extensions/TestDecorator.php b/PHPUnit/Extensions/TestDecorator.php index 18f0b13e9b1..9662064a883 100644 --- a/PHPUnit/Extensions/TestDecorator.php +++ b/PHPUnit/Extensions/TestDecorator.php @@ -137,8 +137,12 @@ public function getTest() * @param PHPUnit_Framework_TestResult $result * @return PHPUnit_Framework_TestResult */ - public function run(PHPUnit_Framework_TestResult $result = NULL) + public function run($result = NULL) { + if ($result !== NULL && !$result instanceof PHPUnit_Framework_TestResult) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'PHPUnit_Framework_TestResult'); + } + if ($result === NULL) { $result = $this->createResult(); } diff --git a/PHPUnit/Framework/Comparator/SplObjectStorage.php b/PHPUnit/Framework/Comparator/SplObjectStorage.php index aebb7cfec44..e65768f1433 100644 --- a/PHPUnit/Framework/Comparator/SplObjectStorage.php +++ b/PHPUnit/Framework/Comparator/SplObjectStorage.php @@ -86,7 +86,7 @@ public function accepts($expected, $actual) public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) { foreach ($actual as $object) { - if (!$expected->contains($object)) { + if (!$expected->offsetExists($object)) { throw new PHPUnit_Framework_ComparisonFailure( $expected, $actual, @@ -99,7 +99,7 @@ public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FAL } foreach ($expected as $object) { - if (!$actual->contains($object)) { + if (!$actual->offsetExists($object)) { throw new PHPUnit_Framework_ComparisonFailure( $expected, $actual, diff --git a/PHPUnit/Framework/Constraint.php b/PHPUnit/Framework/Constraint.php index ded42147f42..fd7dc116dfb 100644 --- a/PHPUnit/Framework/Constraint.php +++ b/PHPUnit/Framework/Constraint.php @@ -126,8 +126,12 @@ public function count() * @param PHPUnit_Framework_ComparisonFailure $comparisonFailure * @throws PHPUnit_Framework_ExpectationFailedException */ - protected function fail($other, $description, PHPUnit_Framework_ComparisonFailure $comparisonFailure = NULL) + protected function fail($other, $description, $comparisonFailure = NULL) { + if ($comparisonFailure !== NULL && !$comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'PHPUnit_Framework_ComparisonFailure'); + } + $failureDescription = sprintf( 'Failed asserting that %s.', $this->failureDescription($other) diff --git a/PHPUnit/Framework/Constraint/TraversableContains.php b/PHPUnit/Framework/Constraint/TraversableContains.php index aa00b2dc3ec..2d49d9de807 100644 --- a/PHPUnit/Framework/Constraint/TraversableContains.php +++ b/PHPUnit/Framework/Constraint/TraversableContains.php @@ -94,7 +94,7 @@ public function __construct($value, $checkForObjectIdentity = TRUE) protected function matches($other) { if ($other instanceof SplObjectStorage) { - return $other->contains($this->value); + return $other->offsetExists($this->value); } if (is_object($this->value)) { diff --git a/PHPUnit/Framework/Error.php b/PHPUnit/Framework/Error.php index c599e18d2ee..6cd5100ee50 100644 --- a/PHPUnit/Framework/Error.php +++ b/PHPUnit/Framework/Error.php @@ -65,8 +65,12 @@ class PHPUnit_Framework_Error extends Exception * @param integer $line * @param Exception $previous */ - public function __construct($message, $code, $file, $line, Exception $previous = NULL) + public function __construct($message, $code, $file, $line, $previous = NULL) { + if ($previous !== NULL && !$previous instanceof Exception) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(5, 'Exception'); + } + parent::__construct($message, $code, $previous); $this->file = $file; diff --git a/PHPUnit/Framework/ExpectationFailedException.php b/PHPUnit/Framework/ExpectationFailedException.php index cdb48cbba3f..9973cf63012 100644 --- a/PHPUnit/Framework/ExpectationFailedException.php +++ b/PHPUnit/Framework/ExpectationFailedException.php @@ -65,8 +65,15 @@ class PHPUnit_Framework_ExpectationFailedException extends PHPUnit_Framework_Ass */ protected $comparisonFailure; - public function __construct($message, PHPUnit_Framework_ComparisonFailure $comparisonFailure = NULL, Exception $previous = NULL) + public function __construct($message, $comparisonFailure = NULL, $previous = NULL) { + if ($comparisonFailure !== NULL && !$comparisonFailure instanceof PHPUnit_Framework_ComparisonFailure) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'PHPUnit_Framework_ComparisonFailure'); + } + if ($previous !== NULL && !$previous instanceof Exception) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'Exception'); + } + $this->comparisonFailure = $comparisonFailure; parent::__construct($message, 0, $previous); diff --git a/PHPUnit/Framework/Test.php b/PHPUnit/Framework/Test.php index d77af35941a..a198028f9a5 100644 --- a/PHPUnit/Framework/Test.php +++ b/PHPUnit/Framework/Test.php @@ -62,5 +62,5 @@ interface PHPUnit_Framework_Test extends Countable * @param PHPUnit_Framework_TestResult $result * @return PHPUnit_Framework_TestResult */ - public function run(PHPUnit_Framework_TestResult $result = NULL); + public function run($result = NULL); } diff --git a/PHPUnit/Framework/TestCase.php b/PHPUnit/Framework/TestCase.php index 51ce9ad1289..3fc1e05bbce 100644 --- a/PHPUnit/Framework/TestCase.php +++ b/PHPUnit/Framework/TestCase.php @@ -676,8 +676,12 @@ public function hasFailed() * @return PHPUnit_Framework_TestResult * @throws PHPUnit_Framework_Exception */ - public function run(PHPUnit_Framework_TestResult $result = NULL) + public function run($result = NULL) { + if ($result !== NULL && !$result instanceof PHPUnit_Framework_TestResult) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'PHPUnit_Framework_TestResult'); + } + if ($result === NULL) { $result = $this->createResult(); } @@ -1673,21 +1677,29 @@ public static function onConsecutiveCalls() * @return string * @since Method available since Release 3.2.1 */ - protected function dataToString($data) + protected function dataToString($data, $depth = 0) { + // guard against infinite recursion from self-referencing arrays + // that print_r's *RECURSION* detection might miss + if ($depth > 25) { + return '*DEEP_NESTED*'; + } + $result = array(); // 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($data, TRUE), $matches); + // suppress warnings from NAN/INF string coercion on PHP 8.5+ to avoid + // infinite recursion: warning → error handler → dataToString → print_r → warning + preg_match_all('/\n \[(\w+)\] => Array\s+\*RECURSION\*/', @print_r($data, 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 ((string)(int)$recursiveKey === $recursiveKey) { + $recursiveKeys[$key] = (int)$recursiveKey; } } @@ -1697,7 +1709,7 @@ protected function dataToString($data) } else if (is_array($_data)) { - $result[] = 'array(' . $this->dataToString($_data) . ')'; + $result[] = 'array(' . $this->dataToString($_data, $depth + 1) . ')'; } else if (is_object($_data)) { diff --git a/PHPUnit/Framework/TestSuite.php b/PHPUnit/Framework/TestSuite.php index 4faad4ace27..4173adc5df8 100644 --- a/PHPUnit/Framework/TestSuite.php +++ b/PHPUnit/Framework/TestSuite.php @@ -625,8 +625,12 @@ public function getGroups() * @return PHPUnit_Framework_TestResult * @throws PHPUnit_Framework_Exception */ - public function run(PHPUnit_Framework_TestResult $result = NULL, $filter = FALSE, array $groups = array(), array $excludeGroups = array(), $processIsolation = FALSE) + public function run($result = NULL, $filter = FALSE, array $groups = array(), array $excludeGroups = array(), $processIsolation = FALSE) { + if ($result !== NULL && !$result instanceof PHPUnit_Framework_TestResult) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'PHPUnit_Framework_TestResult'); + } + if ($result === NULL) { $result = $this->createResult(); } @@ -690,7 +694,7 @@ class_exists($this->name, false) && foreach ($groups as $group) { if (isset($this->groups[$group])) { foreach ($this->groups[$group] as $test) { - $tests->attach($test); + $tests->offsetSet($test, null); } } } diff --git a/PHPUnit/TextUI/TestRunner.php b/PHPUnit/TextUI/TestRunner.php index d3e273018cd..22f8beb20de 100644 --- a/PHPUnit/TextUI/TestRunner.php +++ b/PHPUnit/TextUI/TestRunner.php @@ -86,8 +86,15 @@ class PHPUnit_TextUI_TestRunner extends PHPUnit_Runner_BaseTestRunner * @param PHP_CodeCoverage_Filter $filter * @since Method available since Release 3.4.0 */ - public function __construct(PHPUnit_Runner_TestSuiteLoader $loader = NULL, PHP_CodeCoverage_Filter $filter = NULL) + public function __construct($loader = NULL, $filter = NULL) { + if ($loader !== NULL && !$loader instanceof PHPUnit_Runner_TestSuiteLoader) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'PHPUnit_Runner_TestSuiteLoader'); + } + if ($filter !== NULL && !$filter instanceof PHP_CodeCoverage_Filter) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'PHP_CodeCoverage_Filter'); + } + if ($filter === NULL) { $filter = new PHP_CodeCoverage_Filter; } diff --git a/PHPUnit/Util/Class.php b/PHPUnit/Util/Class.php index 765db545c87..ce86ab4ff97 100644 --- a/PHPUnit/Util/Class.php +++ b/PHPUnit/Util/Class.php @@ -320,9 +320,12 @@ public static function getObjectAttribute($object, $attributeName) if (!$attribute || $attribute->isPublic()) { return $object->$attributeName; } - $attribute->setAccessible(TRUE); + if (PHP_VERSION_ID < 80100) { + $attribute->setAccessible(TRUE); + } $value = $attribute->getValue($object); - $attribute->setAccessible(FALSE); + + return $value; } diff --git a/PHPUnit/Util/GlobalState.php b/PHPUnit/Util/GlobalState.php index 008e691e98c..be18c7ad0b4 100644 --- a/PHPUnit/Util/GlobalState.php +++ b/PHPUnit/Util/GlobalState.php @@ -327,7 +327,9 @@ public static function backupStaticAttributes(array $blacklist) if (!isset($blacklist[$declaredClasses[$i]]) || !in_array($name, $blacklist[$declaredClasses[$i]])) { - $attribute->setAccessible(TRUE); + if (PHP_VERSION_ID < 80100) { + $attribute->setAccessible(TRUE); + } $value = $attribute->getValue(); if (!$value instanceof Closure) { @@ -349,7 +351,9 @@ public static function restoreStaticAttributes() foreach (self::$staticAttributes as $className => $staticAttributes) { foreach ($staticAttributes as $name => $value) { $reflector = new ReflectionProperty($className, $name); - $reflector->setAccessible(TRUE); + if (PHP_VERSION_ID < 80100) { + $reflector->setAccessible(TRUE); + } // two-arg form: single-arg setValue() for static properties is deprecated in PHP 8.3 $reflector->setValue(null, unserialize($value)); } diff --git a/PHPUnit/Util/PHP.php b/PHPUnit/Util/PHP.php index 27b7f3790f2..a1ffef80faf 100644 --- a/PHPUnit/Util/PHP.php +++ b/PHPUnit/Util/PHP.php @@ -159,8 +159,15 @@ public static function factory() * @return array|null * @throws PHPUnit_Framework_Exception */ - public function runJob($job, PHPUnit_Framework_Test $test = NULL, PHPUnit_Framework_TestResult $result = NULL) + public function runJob($job, $test = NULL, $result = NULL) { + if ($test !== NULL && !$test instanceof PHPUnit_Framework_Test) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'PHPUnit_Framework_Test'); + } + if ($result !== NULL && !$result instanceof PHPUnit_Framework_TestResult) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'PHPUnit_Framework_TestResult'); + } + $process = proc_open( $this->getPhpBinary(), array( diff --git a/PHPUnit/Util/Type.php b/PHPUnit/Util/Type.php index de7a52048fb..cd63fad7a61 100644 --- a/PHPUnit/Util/Type.php +++ b/PHPUnit/Util/Type.php @@ -127,7 +127,7 @@ protected static function recursiveExport(&$value, $indentation, $processed = nu return 'false'; } - if (is_float($value) && floatval(intval($value)) === $value) { + if (is_float($value) && is_finite($value) && floatval(intval($value)) === $value) { return "$value.0"; } diff --git a/PHPUnit/Util/Type/ExportContext.php b/PHPUnit/Util/Type/ExportContext.php index 5bdca020c89..3e0b4cfa535 100644 --- a/PHPUnit/Util/Type/ExportContext.php +++ b/PHPUnit/Util/Type/ExportContext.php @@ -141,8 +141,8 @@ protected function addArray(array &$value) */ protected function addObject($value) { - if (!$this->objects->contains($value)) { - $this->objects->attach($value); + if (!$this->objects->offsetExists($value)) { + $this->objects->offsetSet($value, null); } return spl_object_hash($value); @@ -180,7 +180,7 @@ protected function containsArray(array &$value) */ protected function containsObject($value) { - if ($this->objects->contains($value)) { + if ($this->objects->offsetExists($value)) { return spl_object_hash($value); } diff --git a/Tests/Framework/AssertTest.php b/Tests/Framework/AssertTest.php index 5517d48fc31..e0bc5369669 100644 --- a/Tests/Framework/AssertTest.php +++ b/Tests/Framework/AssertTest.php @@ -101,7 +101,7 @@ public function testAssertSplObjectStorageContainsObject() $a = new stdClass; $b = new stdClass; $c = new SplObjectStorage; - $c->attach($a); + $c->offsetSet($a); $this->assertContains($a, $c); @@ -412,7 +412,7 @@ public function testAssertSplObjectStorageNotContainsObject() $a = new stdClass; $b = new stdClass; $c = new SplObjectStorage; - $c->attach($a); + $c->offsetSet($a); $this->assertNotContains($b, $c); @@ -633,9 +633,9 @@ protected function notEqualValues() $object2 = new SampleClass(16, 23, 42); $object3 = new SampleClass( 4, 8, 15); $storage1 = new SplObjectStorage; - $storage1->attach($object1); + $storage1->offsetSet($object1); $storage2 = new SplObjectStorage; - $storage2->attach($object3); // same content, different object + $storage2->offsetSet($object3); // same content, different object // cannot use $filesDirectory, because neither setUp() nor // setUpBeforeClass() are executed before the data providers @@ -724,9 +724,9 @@ protected function equalValues() $object1 = new SampleClass(4, 8, 15); $object2 = new SampleClass(4, 8, 15); $storage1 = new SplObjectStorage; - $storage1->attach($object1); + $storage1->offsetSet($object1); $storage2 = new SplObjectStorage; - $storage2->attach($object1); + $storage2->offsetSet($object1); return array( // strings diff --git a/Tests/Framework/ConstraintTest.php b/Tests/Framework/ConstraintTest.php index 4d4ec230105..46de9a26bbf 100644 --- a/Tests/Framework/ConstraintTest.php +++ b/Tests/Framework/ConstraintTest.php @@ -733,10 +733,10 @@ public function isEqualProvider() $d->c = $c; $storage1 = new SplObjectStorage; - $storage1->attach($a); - $storage1->attach($b); + $storage1->offsetSet($a); + $storage1->offsetSet($b); $storage2 = new SplObjectStorage; - $storage2->attach($b); + $storage2->offsetSet($b); $storage1hash = spl_object_hash($storage1); $storage2hash = spl_object_hash($storage2); @@ -3200,7 +3200,7 @@ public function testConstraintSplObjectStorageContains() $storage = new SplObjectStorage; $this->assertFalse($constraint->evaluate($storage, '', TRUE)); - $storage->attach($object); + $storage->offsetSet($object); $this->assertTrue($constraint->evaluate($storage, '', TRUE)); try { diff --git a/Tests/_files/DoubleTestCase.php b/Tests/_files/DoubleTestCase.php index 1e8380a1d0d..1c04612e73b 100644 --- a/Tests/_files/DoubleTestCase.php +++ b/Tests/_files/DoubleTestCase.php @@ -14,8 +14,12 @@ public function count() return 2; } - public function run(PHPUnit_Framework_TestResult $result = NULL) + public function run($result = NULL) { + if ($result !== NULL && !$result instanceof PHPUnit_Framework_TestResult) { + throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'PHPUnit_Framework_TestResult'); + } + $result->startTest($this); $this->testCase->runBare();