4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Debug\Tests\Exception;
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Debug\Exception\FlattenException;
16 use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
17 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
18 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
19 use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
20 use Symfony\Component\HttpKernel\Exception\GoneHttpException;
21 use Symfony\Component\HttpKernel\Exception\LengthRequiredHttpException;
22 use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
23 use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
24 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
25 use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;
26 use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException;
27 use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
28 use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
29 use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
30 use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
32 class FlattenExceptionTest extends TestCase
34 public function testStatusCode()
36 $flattened = FlattenException::create(new \RuntimeException(), 403);
37 $this->assertEquals('403', $flattened->getStatusCode());
39 $flattened = FlattenException::create(new \RuntimeException());
40 $this->assertEquals('500', $flattened->getStatusCode());
42 $flattened = FlattenException::create(new NotFoundHttpException());
43 $this->assertEquals('404', $flattened->getStatusCode());
45 $flattened = FlattenException::create(new UnauthorizedHttpException('Basic realm="My Realm"'));
46 $this->assertEquals('401', $flattened->getStatusCode());
48 $flattened = FlattenException::create(new BadRequestHttpException());
49 $this->assertEquals('400', $flattened->getStatusCode());
51 $flattened = FlattenException::create(new NotAcceptableHttpException());
52 $this->assertEquals('406', $flattened->getStatusCode());
54 $flattened = FlattenException::create(new ConflictHttpException());
55 $this->assertEquals('409', $flattened->getStatusCode());
57 $flattened = FlattenException::create(new MethodNotAllowedHttpException(array('POST')));
58 $this->assertEquals('405', $flattened->getStatusCode());
60 $flattened = FlattenException::create(new AccessDeniedHttpException());
61 $this->assertEquals('403', $flattened->getStatusCode());
63 $flattened = FlattenException::create(new GoneHttpException());
64 $this->assertEquals('410', $flattened->getStatusCode());
66 $flattened = FlattenException::create(new LengthRequiredHttpException());
67 $this->assertEquals('411', $flattened->getStatusCode());
69 $flattened = FlattenException::create(new PreconditionFailedHttpException());
70 $this->assertEquals('412', $flattened->getStatusCode());
72 $flattened = FlattenException::create(new PreconditionRequiredHttpException());
73 $this->assertEquals('428', $flattened->getStatusCode());
75 $flattened = FlattenException::create(new ServiceUnavailableHttpException());
76 $this->assertEquals('503', $flattened->getStatusCode());
78 $flattened = FlattenException::create(new TooManyRequestsHttpException());
79 $this->assertEquals('429', $flattened->getStatusCode());
81 $flattened = FlattenException::create(new UnsupportedMediaTypeHttpException());
82 $this->assertEquals('415', $flattened->getStatusCode());
84 if (class_exists(SuspiciousOperationException::class)) {
85 $flattened = FlattenException::create(new SuspiciousOperationException());
86 $this->assertEquals('400', $flattened->getStatusCode());
90 public function testHeadersForHttpException()
92 $flattened = FlattenException::create(new MethodNotAllowedHttpException(array('POST')));
93 $this->assertEquals(array('Allow' => 'POST'), $flattened->getHeaders());
95 $flattened = FlattenException::create(new UnauthorizedHttpException('Basic realm="My Realm"'));
96 $this->assertEquals(array('WWW-Authenticate' => 'Basic realm="My Realm"'), $flattened->getHeaders());
98 $flattened = FlattenException::create(new ServiceUnavailableHttpException('Fri, 31 Dec 1999 23:59:59 GMT'));
99 $this->assertEquals(array('Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'), $flattened->getHeaders());
101 $flattened = FlattenException::create(new ServiceUnavailableHttpException(120));
102 $this->assertEquals(array('Retry-After' => 120), $flattened->getHeaders());
104 $flattened = FlattenException::create(new TooManyRequestsHttpException('Fri, 31 Dec 1999 23:59:59 GMT'));
105 $this->assertEquals(array('Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'), $flattened->getHeaders());
107 $flattened = FlattenException::create(new TooManyRequestsHttpException(120));
108 $this->assertEquals(array('Retry-After' => 120), $flattened->getHeaders());
112 * @dataProvider flattenDataProvider
114 public function testFlattenHttpException(\Exception $exception)
116 $flattened = FlattenException::create($exception);
117 $flattened2 = FlattenException::create($exception);
119 $flattened->setPrevious($flattened2);
121 $this->assertEquals($exception->getMessage(), $flattened->getMessage(), 'The message is copied from the original exception.');
122 $this->assertEquals($exception->getCode(), $flattened->getCode(), 'The code is copied from the original exception.');
123 $this->assertInstanceOf($flattened->getClass(), $exception, 'The class is set to the class of the original exception');
127 * @dataProvider flattenDataProvider
129 public function testPrevious(\Exception $exception)
131 $flattened = FlattenException::create($exception);
132 $flattened2 = FlattenException::create($exception);
134 $flattened->setPrevious($flattened2);
136 $this->assertSame($flattened2, $flattened->getPrevious());
138 $this->assertSame(array($flattened2), $flattened->getAllPrevious());
144 public function testPreviousError()
146 $exception = new \Exception('test', 123, new \ParseError('Oh noes!', 42));
148 $flattened = FlattenException::create($exception)->getPrevious();
150 $this->assertEquals($flattened->getMessage(), 'Parse error: Oh noes!', 'The message is copied from the original exception.');
151 $this->assertEquals($flattened->getCode(), 42, 'The code is copied from the original exception.');
152 $this->assertEquals($flattened->getClass(), 'Symfony\Component\Debug\Exception\FatalThrowableError', 'The class is set to the class of the original exception');
156 * @dataProvider flattenDataProvider
158 public function testLine(\Exception $exception)
160 $flattened = FlattenException::create($exception);
161 $this->assertSame($exception->getLine(), $flattened->getLine());
165 * @dataProvider flattenDataProvider
167 public function testFile(\Exception $exception)
169 $flattened = FlattenException::create($exception);
170 $this->assertSame($exception->getFile(), $flattened->getFile());
174 * @dataProvider flattenDataProvider
176 public function testToArray(\Exception $exception)
178 $flattened = FlattenException::create($exception);
179 $flattened->setTrace(array(), 'foo.php', 123);
181 $this->assertEquals(array(
184 'class' => 'Exception',
185 'trace' => array(array(
186 'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => 'foo.php', 'line' => 123,
190 ), $flattened->toArray());
193 public function flattenDataProvider()
196 array(new \Exception('test', 123)),
200 public function testArguments()
202 $dh = opendir(__DIR__);
205 $incomplete = unserialize('O:14:"BogusTestClass":0:{}');
207 $exception = $this->createException(array(
208 (object) array('foo' => 1),
209 new NotFoundHttpException(),
227 $flattened = FlattenException::create($exception);
228 $trace = $flattened->getTrace();
229 $args = $trace[1]['args'];
230 $array = $args[0][1];
236 $this->assertSame(array('object', 'stdClass'), $array[$i++]);
237 $this->assertSame(array('object', 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'), $array[$i++]);
238 $this->assertSame(array('incomplete-object', 'BogusTestClass'), $array[$i++]);
239 $this->assertSame(array('resource', \defined('HHVM_VERSION') ? 'Directory' : 'stream'), $array[$i++]);
240 $this->assertSame(array('resource', 'stream'), $array[$i++]);
242 $args = $array[$i++];
243 $this->assertSame($args[0], 'object');
244 $this->assertTrue('Closure' === $args[1] || is_subclass_of($args[1], '\Closure'), 'Expect object class name to be Closure or a subclass of Closure.');
246 $this->assertSame(array('array', array(array('integer', 1), array('integer', 2))), $array[$i++]);
247 $this->assertSame(array('array', array('foo' => array('integer', 123))), $array[$i++]);
248 $this->assertSame(array('null', null), $array[$i++]);
249 $this->assertSame(array('boolean', true), $array[$i++]);
250 $this->assertSame(array('boolean', false), $array[$i++]);
251 $this->assertSame(array('integer', 0), $array[$i++]);
252 $this->assertSame(array('float', 0.0), $array[$i++]);
253 $this->assertSame(array('string', '0'), $array[$i++]);
254 $this->assertSame(array('string', ''), $array[$i++]);
255 $this->assertSame(array('float', INF), $array[$i++]);
257 // assertEquals() does not like NAN values.
258 $this->assertEquals($array[$i][0], 'float');
259 $this->assertTrue(is_nan($array[$i++][1]));
262 public function testRecursionInArguments()
265 $a = array('foo', array(2, &$a));
266 $exception = $this->createException($a);
268 $flattened = FlattenException::create($exception);
269 $trace = $flattened->getTrace();
270 $this->assertContains('*DEEP NESTED ARRAY*', serialize($trace));
273 public function testTooBigArray()
276 for ($i = 0; $i < 20; ++$i) {
277 for ($j = 0; $j < 50; ++$j) {
278 for ($k = 0; $k < 10; ++$k) {
279 $a[$i][$j][$k] = 'value';
285 $exception = $this->createException($a);
287 $flattened = FlattenException::create($exception);
288 $trace = $flattened->getTrace();
290 $this->assertSame($trace[1]['args'][0], array('array', array('array', '*SKIPPED over 10000 entries*')));
292 $serializeTrace = serialize($trace);
294 $this->assertContains('*SKIPPED over 10000 entries*', $serializeTrace);
295 $this->assertNotContains('*value1*', $serializeTrace);
298 private function createException($foo)
300 return new \Exception();