Skip to content

Commit 342786a

Browse files
feature symfony#16709 [Bridge\PhpUnit] Display the stack trace of a deprecation on-demand (nicolas-grekas)
This PR was merged into the 2.8 branch. Discussion ---------- [Bridge\PhpUnit] Display the stack trace of a deprecation on-demand | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This PR has been essential into making symfony#16708, and I think everyone working on a 3.0 migration will need this. Example: ``` $ SYMFONY_DEPRECATIONS_HELPER=/FormExtensionBootstrap3LayoutTest/ ./phpunit src/Symfony/Bridge/Twig/ PHPUnit 4.8.18 by Sebastian Bergmann and contributors. Testing src/Symfony/Bridge/Twig/ ................................................ Remaining deprecation triggered by Symfony\Bridge\Twig\Tests\Extension\FormExtensionBootstrap3LayoutTest::testSingleChoiceGrouped: The value "false" for the "choices_as_values" option is deprecated since version 2.8 and will not be supported anymore in 3.0. Set this option to "true" and flip the contents of the "choices" option instead. Stack trace: #0 src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php(286): trigger_error() #1 src/Symfony/Component/OptionsResolver/OptionsResolver.php(962): Symfony\Component\Form\Extension\Core\Type\ChoiceType->Symfony\Component\Form\Extension\Core\Type\{closure}() #2 src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php(277): Symfony\Component\OptionsResolver\OptionsResolver->offsetGet() #3 src/Symfony/Component/OptionsResolver/OptionsResolver.php(962): Symfony\Component\Form\Extension\Core\Type\ChoiceType->Symfony\Component\Form\Extension\Core\Type\{closure}() symfony#4 src/Symfony/Component/OptionsResolver/OptionsResolver.php(791): Symfony\Component\OptionsResolver\OptionsResolver->offsetGet() symfony#5 src/Symfony/Component/Form/ResolvedFormType.php(156): Symfony\Component\OptionsResolver\OptionsResolver->resolve() symfony#6 src/Symfony/Component/Form/FormFactory.php(119): Symfony\Component\Form\ResolvedFormType->createBuilder() symfony#7 src/Symfony/Component/Form/FormFactory.php(48): Symfony\Component\Form\FormFactory->createNamedBuilder() symfony#8 src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php(540): Symfony\Component\Form\FormFactory->createNamed() symfony#9 [internal function]: Symfony\Component\Form\Tests\AbstractBootstrap3LayoutTest->testSingleChoiceGrouped() symfony#10 {main} KO src/Symfony/Bridge/Twig/ ``` Commits ------- 5a88fb6 [Bridge\PhpUnit] Display the stack trace of a deprecation on-demand
2 parents fad3d38 + 5a88fb6 commit 342786a

File tree

3 files changed

+38
-8
lines changed

3 files changed

+38
-8
lines changed

src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,37 @@ public static function register($mode = false)
4747
// No-op
4848
}
4949

50-
if (0 !== error_reporting()) {
51-
$group = 'unsilenced';
52-
$ref = &$deprecations[$group][$msg]['count'];
53-
++$ref;
54-
} elseif (isset($trace[$i]['object']) || isset($trace[$i]['class'])) {
50+
if (isset($trace[$i]['object']) || isset($trace[$i]['class'])) {
5551
$class = isset($trace[$i]['object']) ? get_class($trace[$i]['object']) : $trace[$i]['class'];
5652
$method = $trace[$i]['function'];
5753

58-
$group = 0 === strpos($method, 'testLegacy') || 0 === strpos($method, 'provideLegacy') || 0 === strpos($method, 'getLegacy') || strpos($class, '\Legacy') || in_array('legacy', \PHPUnit_Util_Test::getGroups($class, $method), true) ? 'legacy' : 'remaining';
54+
if (0 !== error_reporting()) {
55+
$group = 'unsilenced';
56+
} elseif (0 === strpos($method, 'testLegacy')
57+
|| 0 === strpos($method, 'provideLegacy')
58+
|| 0 === strpos($method, 'getLegacy')
59+
|| strpos($class, '\Legacy')
60+
|| in_array('legacy', \PHPUnit_Util_Test::getGroups($class, $method), true)
61+
) {
62+
$group = 'legacy';
63+
} else {
64+
$group = 'remaining';
65+
}
66+
67+
if (isset($mode[0]) && '/' === $mode[0] && preg_match($mode, $class.'::'.$method)) {
68+
$e = new \Exception($msg);
69+
$r = new \ReflectionProperty($e, 'trace');
70+
$r->setAccessible(true);
71+
$r->setValue($e, array_slice($trace, 1, $i));
5972

73+
echo "\n".ucfirst($group).' deprecation triggered by '.$class.'::'.$method.':';
74+
echo "\n".$msg;
75+
echo "\nStack trace:";
76+
echo "\n".str_replace(' '.getcwd().DIRECTORY_SEPARATOR, ' ', $e->getTraceAsString());
77+
echo "\n";
78+
79+
exit(1);
80+
}
6081
if ('legacy' !== $group && 'weak' !== $mode) {
6182
$ref = &$deprecations[$group][$msg]['count'];
6283
++$ref;
@@ -78,7 +99,7 @@ public static function register($mode = false)
7899
restore_error_handler();
79100
self::register($mode);
80101
}
81-
} else {
102+
} elseif (!isset($mode[0]) || '/' !== $mode[0]) {
82103
self::$isRegistered = true;
83104
if (self::hasColorSupport()) {
84105
$colorize = function ($str, $red) {

src/Symfony/Bridge/PhpUnit/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ It comes with the following features:
88
* disable the garbage collector;
99
* enforce a consistent `C` locale;
1010
* auto-register `class_exists` to load Doctrine annotations;
11-
* print a user deprecation notices summary at the end of the test suite.
11+
* print a user deprecation notices summary at the end of the test suite;
12+
* display the stack trace of a deprecation on-demand.
1213

1314
By default any non-legacy-tagged or any non-@-silenced deprecation notices will
1415
make tests fail.
@@ -51,3 +52,9 @@ You have to decide either to:
5152
* update your code to not use deprecated interfaces anymore, thus gaining better
5253
forward compatibility;
5354
* or move them to the **Legacy** section (by using one of the above way).
55+
56+
In you need to inspect the stack trace of a particular deprecation triggered by
57+
one of your unit tests, you can set the `SYMFONY_DEPRECATIONS_HELPER` env var to
58+
a regexp that matches this test case's `class::method` name. For example,
59+
`SYMFONY_DEPRECATIONS_HELPER=/^MyTest::testMethod$/ phpunit` will stop your test
60+
suite once a deprecation is triggered by the `MyTest::testMethod` test.

src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
* ```
4242
*
4343
* @author Bernhard Schussek <[email protected]>
44+
*
45+
* @deprecated since version 2.8, to be removed in 3.0. Use ArrayChoiceList instead.
4446
*/
4547
class ArrayKeyChoiceList extends ArrayChoiceList
4648
{

0 commit comments

Comments
 (0)