|
11 | 11 |
|
12 | 12 | namespace Symfony\Bridge\PhpUnit; |
13 | 13 |
|
14 | | -use Doctrine\Common\Annotations\AnnotationRegistry; |
| 14 | +use PHPUnit\Framework\BaseTestListener; |
| 15 | +use PHPUnit\Framework\Test; |
| 16 | +use PHPUnit\Framework\TestSuite; |
| 17 | +use PHPUnit\Framework\Warning; |
| 18 | + |
| 19 | +if (class_exists('PHPUnit_Framework_BaseTestListener')) { |
| 20 | + class_alias('Symfony\Bridge\PhpUnit\TextUI\Legacy\SymfonyTestsListener', 'Symfony\Bridge\PhpUnit\SymfonyTestsListener'); |
| 21 | + |
| 22 | + return; |
| 23 | +} |
15 | 24 |
|
16 | 25 | /** |
17 | 26 | * Collects and replays skipped tests. |
18 | 27 | * |
19 | 28 | * @author Nicolas Grekas <p@tchwork.com> |
| 29 | + * |
| 30 | + * @final |
20 | 31 | */ |
21 | | -class SymfonyTestsListener extends \PHPUnit_Framework_BaseTestListener |
| 32 | +class SymfonyTestsListener extends BaseTestListener |
22 | 33 | { |
23 | | - private static $globallyEnabled = false; |
24 | | - private $state = -1; |
25 | | - private $skippedFile = false; |
26 | | - private $wasSkipped = array(); |
27 | | - private $isSkipped = array(); |
28 | | - private $expectedDeprecations = array(); |
29 | | - private $gatheredDeprecations = array(); |
30 | | - private $previousErrorHandler; |
31 | | - private $testsWithWarnings; |
| 34 | + use SymfonyTestsListenerTrait; |
32 | 35 |
|
33 | | - /** |
34 | | - * @param array $mockedNamespaces List of namespaces, indexed by mocked features (time-sensitive or dns-sensitive) |
35 | | - */ |
36 | | - public function __construct(array $mockedNamespaces = array()) |
| 36 | + public function startTestSuite(TestSuite $suite) |
37 | 37 | { |
38 | | - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\DeprecationErrorHandler'] = 1; |
39 | | - \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; |
40 | | - |
41 | | - $warn = false; |
42 | | - foreach ($mockedNamespaces as $type => $namespaces) { |
43 | | - if (!is_array($namespaces)) { |
44 | | - $namespaces = array($namespaces); |
45 | | - } |
46 | | - if (is_int($type)) { |
47 | | - // @deprecated BC with v2.8 to v3.0 |
48 | | - $type = 'time-sensitive'; |
49 | | - $warn = true; |
50 | | - } |
51 | | - if ('time-sensitive' === $type) { |
52 | | - foreach ($namespaces as $ns) { |
53 | | - ClockMock::register($ns.'\DummyClass'); |
54 | | - } |
55 | | - } |
56 | | - if ('dns-sensitive' === $type) { |
57 | | - foreach ($namespaces as $ns) { |
58 | | - DnsMock::register($ns.'\DummyClass'); |
59 | | - } |
60 | | - } |
61 | | - } |
62 | | - if (self::$globallyEnabled) { |
63 | | - $this->state = -2; |
64 | | - } else { |
65 | | - self::$globallyEnabled = true; |
66 | | - if ($warn) { |
67 | | - echo "Clock-mocked namespaces for SymfonyTestsListener need to be nested in a \"time-sensitive\" key. This will be enforced in Symfony 4.0.\n"; |
68 | | - } |
69 | | - } |
| 38 | + return $this->doStartTestSuite($suite); |
70 | 39 | } |
71 | 40 |
|
72 | | - public function __destruct() |
| 41 | + public function addSkippedTest(Test $test, \Exception $e, $time) |
73 | 42 | { |
74 | | - if (0 < $this->state) { |
75 | | - file_put_contents($this->skippedFile, '<?php return '.var_export($this->isSkipped, true).';'); |
76 | | - } |
| 43 | + return $this->doAddSkippedTest($test, $e, $time); |
77 | 44 | } |
78 | 45 |
|
79 | | - public function startTestSuite(\PHPUnit_Framework_TestSuite $suite) |
| 46 | + public function startTest(Test $test) |
80 | 47 | { |
81 | | - $suiteName = $suite->getName(); |
82 | | - $this->testsWithWarnings = array(); |
83 | | - |
84 | | - if (-1 === $this->state) { |
85 | | - echo "Testing $suiteName\n"; |
86 | | - $this->state = 0; |
87 | | - |
88 | | - if (!class_exists('Doctrine\Common\Annotations\AnnotationRegistry', false) && class_exists('Doctrine\Common\Annotations\AnnotationRegistry')) { |
89 | | - AnnotationRegistry::registerLoader('class_exists'); |
90 | | - } |
91 | | - |
92 | | - if ($this->skippedFile = getenv('SYMFONY_PHPUNIT_SKIPPED_TESTS')) { |
93 | | - $this->state = 1; |
94 | | - |
95 | | - if (file_exists($this->skippedFile)) { |
96 | | - $this->state = 2; |
97 | | - |
98 | | - if (!$this->wasSkipped = require $this->skippedFile) { |
99 | | - echo "All tests already ran successfully.\n"; |
100 | | - $suite->setTests(array()); |
101 | | - } |
102 | | - } |
103 | | - } |
104 | | - $testSuites = array($suite); |
105 | | - for ($i = 0; isset($testSuites[$i]); ++$i) { |
106 | | - foreach ($testSuites[$i]->tests() as $test) { |
107 | | - if ($test instanceof \PHPUnit_Framework_TestSuite) { |
108 | | - if (!class_exists($test->getName(), false)) { |
109 | | - $testSuites[] = $test; |
110 | | - continue; |
111 | | - } |
112 | | - $groups = \PHPUnit_Util_Test::getGroups($test->getName()); |
113 | | - if (in_array('time-sensitive', $groups, true)) { |
114 | | - ClockMock::register($test->getName()); |
115 | | - } |
116 | | - if (in_array('dns-sensitive', $groups, true)) { |
117 | | - DnsMock::register($test->getName()); |
118 | | - } |
119 | | - } |
120 | | - } |
121 | | - } |
122 | | - } elseif (2 === $this->state) { |
123 | | - $skipped = array(); |
124 | | - foreach ($suite->tests() as $test) { |
125 | | - if (!$test instanceof \PHPUnit_Framework_TestCase |
126 | | - || isset($this->wasSkipped[$suiteName]['*']) |
127 | | - || isset($this->wasSkipped[$suiteName][$test->getName()])) { |
128 | | - $skipped[] = $test; |
129 | | - } |
130 | | - } |
131 | | - $suite->setTests($skipped); |
132 | | - } |
| 48 | + return $this->doStartTest($test); |
133 | 49 | } |
134 | 50 |
|
135 | | - public function addSkippedTest(\PHPUnit_Framework_Test $test, \Exception $e, $time) |
| 51 | + public function addWarning(Test $test, Warning $e, $time) |
136 | 52 | { |
137 | | - if (0 < $this->state) { |
138 | | - if ($test instanceof \PHPUnit_Framework_TestCase) { |
139 | | - $class = get_class($test); |
140 | | - $method = $test->getName(); |
141 | | - } else { |
142 | | - $class = $test->getName(); |
143 | | - $method = '*'; |
144 | | - } |
145 | | - |
146 | | - $this->isSkipped[$class][$method] = 1; |
147 | | - } |
| 53 | + return $this->doAddWarning($test, $e, $time); |
148 | 54 | } |
149 | 55 |
|
150 | | - public function startTest(\PHPUnit_Framework_Test $test) |
| 56 | + public function endTest(Test $test, $time) |
151 | 57 | { |
152 | | - if (-2 < $this->state && $test instanceof \PHPUnit_Framework_TestCase) { |
153 | | - $groups = \PHPUnit_Util_Test::getGroups(get_class($test), $test->getName(false)); |
154 | | - |
155 | | - if (in_array('time-sensitive', $groups, true)) { |
156 | | - ClockMock::register(get_class($test)); |
157 | | - ClockMock::withClockMock(true); |
158 | | - } |
159 | | - if (in_array('dns-sensitive', $groups, true)) { |
160 | | - DnsMock::register(get_class($test)); |
161 | | - } |
162 | | - |
163 | | - $annotations = \PHPUnit_Util_Test::parseTestMethodAnnotations(get_class($test), $test->getName(false)); |
164 | | - |
165 | | - if (isset($annotations['class']['expectedDeprecation'])) { |
166 | | - $test->getTestResultObject()->addError($test, new \PHPUnit_Framework_AssertionFailedError('`@expectedDeprecation` annotations are not allowed at the class level.'), 0); |
167 | | - } |
168 | | - if (isset($annotations['method']['expectedDeprecation'])) { |
169 | | - if (!in_array('legacy', $groups, true)) { |
170 | | - $test->getTestResultObject()->addError($test, new \PHPUnit_Framework_AssertionFailedError('Only tests with the `@group legacy` annotation can have `@expectedDeprecation`.'), 0); |
171 | | - } |
172 | | - $this->expectedDeprecations = $annotations['method']['expectedDeprecation']; |
173 | | - $this->previousErrorHandler = set_error_handler(array($this, 'handleError')); |
174 | | - } |
175 | | - } |
176 | | - } |
177 | | - |
178 | | - public function addWarning(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_Warning $e, $time) |
179 | | - { |
180 | | - if ($test instanceof \PHPUnit_Framework_TestCase) { |
181 | | - $this->testsWithWarnings[$test->getName()] = true; |
182 | | - } |
183 | | - } |
184 | | - |
185 | | - public function endTest(\PHPUnit_Framework_Test $test, $time) |
186 | | - { |
187 | | - $className = get_class($test); |
188 | | - $classGroups = \PHPUnit_Util_Test::getGroups($className); |
189 | | - $groups = \PHPUnit_Util_Test::getGroups($className, $test->getName(false)); |
190 | | - |
191 | | - if ($this->expectedDeprecations) { |
192 | | - restore_error_handler(); |
193 | | - |
194 | | - if (!in_array($test->getStatus(), array(\PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED, \PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE, \PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE, \PHPUnit_Runner_BaseTestRunner::STATUS_ERROR), true)) { |
195 | | - try { |
196 | | - $prefix = "@expectedDeprecation:\n"; |
197 | | - $test->assertStringMatchesFormat($prefix.'%A '.implode("\n%A ", $this->expectedDeprecations)."\n%A", $prefix.' '.implode("\n ", $this->gatheredDeprecations)."\n"); |
198 | | - } catch (\PHPUnit_Framework_AssertionFailedError $e) { |
199 | | - $test->getTestResultObject()->addFailure($test, $e, $time); |
200 | | - } |
201 | | - } |
202 | | - |
203 | | - $this->expectedDeprecations = $this->gatheredDeprecations = array(); |
204 | | - $this->previousErrorHandler = null; |
205 | | - } |
206 | | - if (-2 < $this->state && $test instanceof \PHPUnit_Framework_TestCase) { |
207 | | - if (in_array('time-sensitive', $groups, true)) { |
208 | | - ClockMock::withClockMock(false); |
209 | | - } |
210 | | - if (in_array('dns-sensitive', $groups, true)) { |
211 | | - DnsMock::withMockedHosts(array()); |
212 | | - } |
213 | | - } |
214 | | - |
215 | | - if ($test instanceof \PHPUnit_Framework_TestCase && 0 === strpos($test->getName(), 'testLegacy') && !isset($this->testsWithWarnings[$test->getName()]) && !in_array('legacy', $groups, true)) { |
216 | | - $result = $test->getTestResultObject(); |
217 | | - |
218 | | - if (method_exists($result, 'addWarning')) { |
219 | | - $result->addWarning($test, new \PHPUnit_Framework_Warning('Using the "testLegacy" prefix to mark tests as legacy is deprecated since version 3.3 and will be removed in 4.0. Use the "@group legacy" notation instead to add the test to the legacy group.'), $time); |
220 | | - } |
221 | | - } |
222 | | - |
223 | | - if ($test instanceof \PHPUnit_Framework_TestCase && strpos($className, '\Legacy') && !isset($this->testsWithWarnings[$test->getName()]) && !in_array('legacy', $classGroups, true)) { |
224 | | - $result = $test->getTestResultObject(); |
225 | | - |
226 | | - if (method_exists($result, 'addWarning')) { |
227 | | - $result->addWarning($test, new \PHPUnit_Framework_Warning('Using the "Legacy" prefix to mark all tests of a class as legacy is deprecated since version 3.3 and will be removed in 4.0. Use the "@group legacy" notation instead to add the test to the legacy group.'), $time); |
228 | | - } |
229 | | - } |
230 | | - } |
231 | | - |
232 | | - public function handleError($type, $msg, $file, $line, $context) |
233 | | - { |
234 | | - if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) { |
235 | | - $h = $this->previousErrorHandler; |
236 | | - |
237 | | - return $h ? $h($type, $msg, $file, $line, $context) : false; |
238 | | - } |
239 | | - if (error_reporting()) { |
240 | | - $msg = 'Unsilenced deprecation: '.$msg; |
241 | | - } |
242 | | - $this->gatheredDeprecations[] = $msg; |
| 58 | + return $this->doEndTest($test, $time); |
243 | 59 | } |
244 | 60 | } |
0 commit comments