Skip to content

Commit 19e3d1f

Browse files
committed
[PhpUnitBridge] Add the ability to expect a deprecation inside a test
1 parent b350c80 commit 19e3d1f

File tree

4 files changed

+141
-25
lines changed

4 files changed

+141
-25
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ install:
195195
# To run a PR with a patched phpunit-bridge, first submit the patch for the
196196
# phpunit-bridge as a separate PR against the next feature-branch then
197197
# uncomment and update the following line with that PR number
198-
#SYMFONY_PHPUNIT_BRIDGE_PR=32886
198+
SYMFONY_PHPUNIT_BRIDGE_PR=35192
199199
200200
if [[ $SYMFONY_PHPUNIT_BRIDGE_PR ]]; then
201201
git fetch --depth=2 origin refs/pull/$SYMFONY_PHPUNIT_BRIDGE_PR/head

src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313

1414
use Doctrine\Common\Annotations\AnnotationRegistry;
1515
use PHPUnit\Framework\AssertionFailedError;
16+
use PHPUnit\Framework\RiskyTestError;
1617
use PHPUnit\Framework\TestCase;
1718
use PHPUnit\Framework\TestSuite;
1819
use PHPUnit\Runner\BaseTestRunner;
1920
use PHPUnit\Util\Blacklist;
2021
use PHPUnit\Util\Test;
2122
use Symfony\Bridge\PhpUnit\ClockMock;
2223
use Symfony\Bridge\PhpUnit\DnsMock;
24+
use Symfony\Bridge\PhpUnit\SymfonyExpectDeprecationTrait;
2325
use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
2426
use Symfony\Component\ErrorHandler\DebugClassLoader;
2527

@@ -32,17 +34,17 @@
3234
*/
3335
class SymfonyTestsListenerTrait
3436
{
37+
public static $expectedDeprecations = array();
38+
public static $previousErrorHandler;
39+
private static $gatheredDeprecations = array();
3540
private static $globallyEnabled = false;
3641
private $state = -1;
3742
private $skippedFile = false;
3843
private $wasSkipped = array();
3944
private $isSkipped = array();
40-
private $expectedDeprecations = array();
41-
private $gatheredDeprecations = array();
42-
private $previousErrorHandler;
4345
private $reportUselessTests;
44-
private $error;
4546
private $runsInSeparateProcess = false;
47+
private $checkNumAssertions = false;
4648

4749
/**
4850
* @param array $mockedNamespaces List of namespaces, indexed by mocked features (time-sensitive or dns-sensitive)
@@ -221,15 +223,17 @@ public function startTest($test)
221223
if (isset($annotations['class']['expectedDeprecation'])) {
222224
$test->getTestResultObject()->addError($test, new AssertionFailedError('`@expectedDeprecation` annotations are not allowed at the class level.'), 0);
223225
}
224-
if (isset($annotations['method']['expectedDeprecation'])) {
225-
if (!\in_array('legacy', $groups, true)) {
226-
$this->error = new AssertionFailedError('Only tests with the `@group legacy` annotation can have `@expectedDeprecation`.');
226+
if (($hasExpectedDeprecationAnnotation = isset($annotations['method']['expectedDeprecation'])) || $this->checkNumAssertions = \in_array(SymfonyExpectDeprecationTrait::class, (new \ReflectionClass($test))->getTraitNames(), true)) {
227+
if ($hasExpectedDeprecationAnnotation) {
228+
self::$expectedDeprecations = $annotations['method']['expectedDeprecation'];
229+
self::$previousErrorHandler = set_error_handler(array($this, 'handleError'));
227230
}
228231

229-
$test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything(false);
232+
if ($this->checkNumAssertions) {
233+
$this->checkNumAssertions = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything() && !$test->doesNotPerformAssertions();
234+
}
230235

231-
$this->expectedDeprecations = $annotations['method']['expectedDeprecation'];
232-
$this->previousErrorHandler = set_error_handler(array($this, 'handleError'));
236+
$test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything(false);
233237
}
234238
}
235239
}
@@ -243,16 +247,19 @@ public function endTest($test, $time)
243247
$className = \get_class($test);
244248
$groups = Test::getGroups($className, $test->getName(false));
245249

250+
if ($this->checkNumAssertions && !self::$expectedDeprecations) {
251+
if (0 === $test->getNumAssertions()) {
252+
$test->getTestResultObject()->addFailure($test, new RiskyTestError('This test did not perform any assertions'), $time);
253+
}
254+
255+
$this->checkNumAssertions = false;
256+
}
257+
246258
if (null !== $this->reportUselessTests) {
247259
$test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything($this->reportUselessTests);
248260
$this->reportUselessTests = null;
249261
}
250262

251-
if ($errored = null !== $this->error) {
252-
$test->getTestResultObject()->addError($test, $this->error, 0);
253-
$this->error = null;
254-
}
255-
256263
if ($this->runsInSeparateProcess) {
257264
$deprecations = file_get_contents($this->runsInSeparateProcess);
258265
unlink($this->runsInSeparateProcess);
@@ -269,24 +276,26 @@ public function endTest($test, $time)
269276
$this->runsInSeparateProcess = false;
270277
}
271278

272-
if ($this->expectedDeprecations) {
279+
if (self::$expectedDeprecations) {
273280
if (!\in_array($test->getStatus(), array(BaseTestRunner::STATUS_SKIPPED, BaseTestRunner::STATUS_INCOMPLETE), true)) {
274-
$test->addToAssertionCount(\count($this->expectedDeprecations));
281+
$test->addToAssertionCount(\count(self::$expectedDeprecations));
275282
}
276283

277284
restore_error_handler();
278285

279-
if (!$errored && !\in_array($test->getStatus(), array(BaseTestRunner::STATUS_SKIPPED, BaseTestRunner::STATUS_INCOMPLETE, BaseTestRunner::STATUS_FAILURE, BaseTestRunner::STATUS_ERROR), true)) {
286+
if (!\in_array('legacy', $groups, true)) {
287+
$test->getTestResultObject()->addError($test, new AssertionFailedError('Only tests with the `@group legacy` annotation can expect a deprecation.'), 0);
288+
} elseif (!\in_array($test->getStatus(), array(BaseTestRunner::STATUS_SKIPPED, BaseTestRunner::STATUS_INCOMPLETE, BaseTestRunner::STATUS_FAILURE, BaseTestRunner::STATUS_ERROR), true)) {
280289
try {
281290
$prefix = "@expectedDeprecation:\n";
282-
$test->assertStringMatchesFormat($prefix.'%A '.implode("\n%A ", $this->expectedDeprecations)."\n%A", $prefix.' '.implode("\n ", $this->gatheredDeprecations)."\n");
291+
$test->assertStringMatchesFormat($prefix.'%A '.implode("\n%A ", self::$expectedDeprecations)."\n%A", $prefix.' '.implode("\n ", self::$gatheredDeprecations)."\n");
283292
} catch (AssertionFailedError $e) {
284293
$test->getTestResultObject()->addFailure($test, $e, $time);
285294
}
286295
}
287296

288-
$this->expectedDeprecations = $this->gatheredDeprecations = array();
289-
$this->previousErrorHandler = null;
297+
self::$expectedDeprecations = self::$gatheredDeprecations = array();
298+
self::$previousErrorHandler = null;
290299
}
291300
if (!$this->runsInSeparateProcess && -2 < $this->state && ($test instanceof \PHPUnit\Framework\TestCase || $test instanceof TestCase)) {
292301
if (\in_array('time-sensitive', $groups, true)) {
@@ -298,10 +307,10 @@ public function endTest($test, $time)
298307
}
299308
}
300309

301-
public function handleError($type, $msg, $file, $line, $context = array())
310+
public static function handleError($type, $msg, $file, $line, $context = array())
302311
{
303312
if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) {
304-
$h = $this->previousErrorHandler;
313+
$h = self::$previousErrorHandler;
305314

306315
return $h ? $h($type, $msg, $file, $line, $context) : false;
307316
}
@@ -314,7 +323,7 @@ public function handleError($type, $msg, $file, $line, $context = array())
314323
if (error_reporting()) {
315324
$msg = 'Unsilenced deprecation: '.$msg;
316325
}
317-
$this->gatheredDeprecations[] = $msg;
326+
self::$gatheredDeprecations[] = $msg;
318327

319328
return null;
320329
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\PhpUnit;
13+
14+
use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait;
15+
16+
trait SymfonyExpectDeprecationTrait
17+
{
18+
/**
19+
* @param string $message
20+
*
21+
* @return void
22+
*/
23+
private function expectDeprecation($message)
24+
{
25+
if (!SymfonyTestsListenerTrait::$previousErrorHandler) {
26+
SymfonyTestsListenerTrait::$previousErrorHandler = set_error_handler(array(SymfonyTestsListenerTrait::class, 'handleError'));
27+
}
28+
29+
SymfonyTestsListenerTrait::$expectedDeprecations[] = $message;
30+
}
31+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\PhpUnit\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\SymfonyExpectDeprecationTrait;
16+
17+
final class SymfonyExpectDeprecationTraitTest extends TestCase
18+
{
19+
use SymfonyExpectDeprecationTrait;
20+
21+
/**
22+
* Do not remove this test in the next major version.
23+
*
24+
* @group legacy
25+
*/
26+
public function testOne()
27+
{
28+
$this->expectDeprecation('foo');
29+
@trigger_error('foo', E_USER_DEPRECATED);
30+
}
31+
32+
/**
33+
* Do not remove this test in the next major version.
34+
*
35+
* @group legacy
36+
*/
37+
public function testMany()
38+
{
39+
$this->expectDeprecation('foo');
40+
$this->expectDeprecation('bar');
41+
@trigger_error('foo', E_USER_DEPRECATED);
42+
@trigger_error('bar', E_USER_DEPRECATED);
43+
}
44+
45+
/**
46+
* Do not remove this test in the next major version.
47+
*
48+
* @group legacy
49+
*
50+
* @expectedDeprecation foo
51+
*/
52+
public function testOneWithAnnotation()
53+
{
54+
$this->expectDeprecation('bar');
55+
@trigger_error('foo', E_USER_DEPRECATED);
56+
@trigger_error('bar', E_USER_DEPRECATED);
57+
}
58+
59+
/**
60+
* Do not remove this test in the next major version.
61+
*
62+
* @group legacy
63+
*
64+
* @expectedDeprecation foo
65+
* @expectedDeprecation bar
66+
*/
67+
public function testManyWithAnnotation()
68+
{
69+
$this->expectDeprecation('ccc');
70+
$this->expectDeprecation('fcy');
71+
@trigger_error('foo', E_USER_DEPRECATED);
72+
@trigger_error('bar', E_USER_DEPRECATED);
73+
@trigger_error('ccc', E_USER_DEPRECATED);
74+
@trigger_error('fcy', E_USER_DEPRECATED);
75+
}
76+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy