From 48e54e756b8dfece25b665a587b2158dcaa889ae Mon Sep 17 00:00:00 2001 From: Derek Date: Mon, 17 Feb 2020 17:06:03 -0500 Subject: [PATCH] Handle eval() failing in Laravel Tinker With Laravel Telescope enabled, it's possible for some Laravel Tinker expressions to fail and output a Telescope stacktrace instead of the original PHP throwable Error. --- src/ExceptionContext.php | 28 ++++++++++++++++++++++ tests/Watchers/ExceptionWatcherTest.php | 31 ++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/ExceptionContext.php b/src/ExceptionContext.php index f94290658..7e1d8da2f 100644 --- a/src/ExceptionContext.php +++ b/src/ExceptionContext.php @@ -2,6 +2,7 @@ namespace Laravel\Telescope; +use Illuminate\Support\Str; use Throwable; class ExceptionContext @@ -13,6 +14,33 @@ class ExceptionContext * @return array */ public static function get(Throwable $exception) + { + return static::getEvalContext($exception) ?? + static::getFileContext($exception); + } + + /** + * Get the exception code context when eval() failed. + * + * @param \Throwable $exception + * @return array|null + */ + protected static function getEvalContext(Throwable $exception) + { + if (Str::contains($exception->getFile(), "eval()'d code")) { + return [ + $exception->getLine() => "eval()'d code", + ]; + } + } + + /** + * Get the exception code context from a file. + * + * @param \Throwable $exception + * @return array + */ + protected static function getFileContext(Throwable $exception) { return collect(explode("\n", file_get_contents($exception->getFile()))) ->slice($exception->getLine() - 10, 20) diff --git a/tests/Watchers/ExceptionWatcherTest.php b/tests/Watchers/ExceptionWatcherTest.php index 5b8cbc172..187f14a84 100644 --- a/tests/Watchers/ExceptionWatcherTest.php +++ b/tests/Watchers/ExceptionWatcherTest.php @@ -2,11 +2,13 @@ namespace Laravel\Telescope\Tests\Watchers; +use ErrorException; use Exception; use Illuminate\Contracts\Debug\ExceptionHandler; use Laravel\Telescope\EntryType; use Laravel\Telescope\Tests\FeatureTestCase; use Laravel\Telescope\Watchers\ExceptionWatcher; +use ParseError; class ExceptionWatcherTest extends FeatureTestCase { @@ -34,10 +36,37 @@ public function test_exception_watcher_register_entries() $this->assertSame(EntryType::EXCEPTION, $entry->type); $this->assertSame(BananaException::class, $entry->content['class']); $this->assertSame(__FILE__, $entry->content['file']); - $this->assertSame(28, $entry->content['line']); + $this->assertSame(30, $entry->content['line']); $this->assertSame('Something went bananas.', $entry->content['message']); $this->assertArrayHasKey('trace', $entry->content); } + + public function test_exception_watcher_register_entries_when_eval_failed() + { + $handler = $this->app->get(ExceptionHandler::class); + + $exception = null; + + try { + eval('if ('); + + $this->fail('eval() was expected to throw "syntax error, unexpected end of file"'); + } catch (ParseError $e) { + // PsySH class ExecutionLoopClosure wraps ParseError in an exception. + $exception = new ErrorException($e->getMessage(), $e->getCode(), 1, $e->getFile(), $e->getLine(), $e); + } + + $handler->report($exception); + + $entry = $this->loadTelescopeEntries()->first(); + + $this->assertSame(EntryType::EXCEPTION, $entry->type); + $this->assertSame(ErrorException::class, $entry->content['class']); + $this->assertStringContainsString("eval()'d code", $entry->content['file']); + $this->assertSame(1, $entry->content['line']); + $this->assertSame('syntax error, unexpected end of file', $entry->content['message']); + $this->assertArrayHasKey('trace', $entry->content); + } } class BananaException extends Exception