diff --git a/src/Runner/DefaultTestResultCache.php b/src/Runner/DefaultTestResultCache.php index 906a28f6d5a..62ee5457192 100644 --- a/src/Runner/DefaultTestResultCache.php +++ b/src/Runner/DefaultTestResultCache.php @@ -93,6 +93,36 @@ public function __construct(?string $filepath = null) $this->cacheFilename = $filepath ?? $_ENV['PHPUNIT_RESULT_CACHE'] ?? self::DEFAULT_RESULT_CACHE_FILENAME; } + public function __serialize(): array + { + return [ + 'defects' => $this->defects, + 'times' => $this->times, + ]; + } + + public function __unserialize(array $data): void + { + if (isset($data['times'])) { + foreach ($data['times'] as $testName => $testTime) { + assert(is_string($testName)); + assert(is_float($testTime)); + $this->times[$testName] = $testTime; + } + } + + if (isset($data['defects'])) { + foreach ($data['defects'] as $testName => $testResult) { + assert(is_string($testName)); + assert(is_int($testResult)); + + if (in_array($testResult, self::ALLOWED_CACHE_TEST_STATUSES, true)) { + $this->defects[$testName] = $testResult; + } + } + } + } + /** * @throws Exception */ @@ -198,10 +228,7 @@ public function clear(): void public function serialize(): string { - return serialize([ - 'defects' => $this->defects, - 'times' => $this->times, - ]); + return serialize($this->__serialize()); } /** @@ -209,25 +236,6 @@ public function serialize(): string */ public function unserialize($serialized): void { - $data = unserialize($serialized); - - if (isset($data['times'])) { - foreach ($data['times'] as $testName => $testTime) { - assert(is_string($testName)); - assert(is_float($testTime)); - $this->times[$testName] = $testTime; - } - } - - if (isset($data['defects'])) { - foreach ($data['defects'] as $testName => $testResult) { - assert(is_string($testName)); - assert(is_int($testResult)); - - if (in_array($testResult, self::ALLOWED_CACHE_TEST_STATUSES, true)) { - $this->defects[$testName] = $testResult; - } - } - } + $this->__unserialize(unserialize($serialized)); } } diff --git a/tests/end-to-end/execution-order/cache-result-legacy.phpt b/tests/end-to-end/execution-order/cache-result-legacy.phpt new file mode 100644 index 00000000000..64e0d9417cb --- /dev/null +++ b/tests/end-to-end/execution-order/cache-result-legacy.phpt @@ -0,0 +1,34 @@ +--SKIPIF-- += 70400) die('skip The new serialization format is tested in cache-result.phpt.'); ?> +--TEST-- +phpunit --order-by=no-depends,reverse --cache-result --cache-result-file ./tests/_files/MultiDependencyTest.php +--FILE-- + --TEST-- phpunit --order-by=no-depends,reverse --cache-result --cache-result-file ./tests/_files/MultiDependencyTest.php --FILE-- @@ -29,4 +31,4 @@ Time: %s, Memory: %s OK, but incomplete, skipped, or risky tests! Tests: 5, Assertions: 3, Skipped: 2. -C:37:"PHPUnit\Runner\DefaultTestResultCache":%d:{a:2:{s:7:"defects";a:2:{s:29:"MultiDependencyTest::testFour";i:1;s:30:"MultiDependencyTest::testThree";i:1;}s:5:"times";a:5:{s:29:"MultiDependencyTest::testFive";d:%f;s:29:"MultiDependencyTest::testFour";d:%f;s:30:"MultiDependencyTest::testThree";d:%f;s:28:"MultiDependencyTest::testTwo";d:%f;s:28:"MultiDependencyTest::testOne";d:%f;}}} +O:37:"PHPUnit\Runner\DefaultTestResultCache":%d:{s:7:"defects";a:2:{s:29:"MultiDependencyTest::testFour";i:1;s:30:"MultiDependencyTest::testThree";i:1;}s:5:"times";a:5:{s:29:"MultiDependencyTest::testFive";d:%f;s:29:"MultiDependencyTest::testFour";d:%f;s:30:"MultiDependencyTest::testThree";d:%f;s:28:"MultiDependencyTest::testTwo";d:%f;s:28:"MultiDependencyTest::testOne";d:%f;}} diff --git a/tests/unit/Runner/TestResultCacheTest.php b/tests/unit/Runner/TestResultCacheTest.php index 2c4cf3d4082..770a27cca29 100644 --- a/tests/unit/Runner/TestResultCacheTest.php +++ b/tests/unit/Runner/TestResultCacheTest.php @@ -43,12 +43,16 @@ public function testDoesClearCacheBeforeLoad(): void public function testShouldNotSerializePassedTestsAsDefectButTimeIsStored(): void { + $expectedSerializedData = PHP_VERSION_ID >= 70400 + ? 'O:37:"PHPUnit\Runner\DefaultTestResultCache":2:{s:7:"defects";a:0:{}s:5:"times";a:1:{s:7:"testOne";d:123;}}' + : 'C:37:"PHPUnit\Runner\DefaultTestResultCache":64:{a:2:{s:7:"defects";a:0:{}s:5:"times";a:1:{s:7:"testOne";d:123;}}}'; + $cache = new DefaultTestResultCache; $cache->setState('testOne', BaseTestRunner::STATUS_PASSED); $cache->setTime('testOne', 123); $data = \serialize($cache); - $this->assertSame('C:37:"PHPUnit\Runner\DefaultTestResultCache":64:{a:2:{s:7:"defects";a:0:{}s:5:"times";a:1:{s:7:"testOne";d:123;}}}', $data); + $this->assertSame($expectedSerializedData, $data); } public function testCanPersistCacheToFile(): void @@ -89,8 +93,18 @@ public function testShouldReturnEmptyCacheFromInvalidFile(): void $this->assertTrue($this->isSerializedEmptyCache(\serialize($cache))); } + public function testUnserializeFromLegacyFormat(): void + { + $cache = \unserialize('C:37:"PHPUnit\Runner\DefaultTestResultCache":44:{a:2:{s:7:"defects";a:0:{}s:5:"times";a:0:{}}}'); + + $this->assertInstanceOf(DefaultTestResultCache::class, $cache); + $this->assertTrue($this->isSerializedEmptyCache(\serialize($cache))); + } + public function isSerializedEmptyCache(string $data): bool { - return $data === 'C:37:"PHPUnit\Runner\DefaultTestResultCache":44:{a:2:{s:7:"defects";a:0:{}s:5:"times";a:0:{}}}'; + return PHP_VERSION_ID >= 70400 + ? $data === 'O:37:"PHPUnit\Runner\DefaultTestResultCache":2:{s:7:"defects";a:0:{}s:5:"times";a:0:{}}' + : $data === 'C:37:"PHPUnit\Runner\DefaultTestResultCache":44:{a:2:{s:7:"defects";a:0:{}s:5:"times";a:0:{}}}'; } }