From 25250bf44ec800a8c6bebc245741f305469ff684 Mon Sep 17 00:00:00 2001 From: n0nag0n Date: Thu, 13 Feb 2025 22:53:46 -0700 Subject: [PATCH 1/2] Added ability to generate new requests/responses on duplicate start() --- flight/Engine.php | 15 +++++++++++++++ flight/net/Request.php | 4 ++-- tests/EngineTest.php | 24 +++++++++++++++++++++++ tests/FlightTest.php | 9 +++++++-- tests/RequestTest.php | 18 +++++++++--------- tests/ViewTest.php | 43 ++++++++++++++++++++++++++++-------------- 6 files changed, 86 insertions(+), 27 deletions(-) diff --git a/flight/Engine.php b/flight/Engine.php index 0a77031..e2c1dc3 100644 --- a/flight/Engine.php +++ b/flight/Engine.php @@ -94,6 +94,9 @@ class Engine /** If the framework has been initialized or not. */ protected bool $initialized = false; + /** If the request has been handled or not. */ + protected bool $requestHandled = false; + public function __construct() { $this->loader = new Loader(); @@ -476,6 +479,18 @@ class Engine { $dispatched = false; $self = $this; + + // This behavior is specifically for test suites, and for async platforms like swoole, workerman, etc. + if ($this->requestHandled === false) { + // not doing much here, just setting the requestHandled flag to true + $this->requestHandled = true; + } else { + // deregister the request and response objects and re-register them with new instances + $this->unregister('request'); + $this->unregister('response'); + $this->register('request', Request::class); + $this->register('response', Response::class); + } $request = $this->request(); $response = $this->response(); $router = $this->router(); diff --git a/flight/net/Request.php b/flight/net/Request.php index f88c770..5164b11 100644 --- a/flight/net/Request.php +++ b/flight/net/Request.php @@ -211,8 +211,8 @@ class Request $this->data->setData($data); } } - // Check PUT, PATCH, DELETE for application/x-www-form-urlencoded data - } else if (in_array($this->method, [ 'PUT', 'DELETE', 'PATCH' ], true) === true) { + // Check PUT, PATCH, DELETE for application/x-www-form-urlencoded data + } elseif (in_array($this->method, [ 'PUT', 'DELETE', 'PATCH' ], true) === true) { $body = $this->getBody(); if ($body !== '') { $data = []; diff --git a/tests/EngineTest.php b/tests/EngineTest.php index e2289c6..857dfb8 100644 --- a/tests/EngineTest.php +++ b/tests/EngineTest.php @@ -174,6 +174,30 @@ class EngineTest extends TestCase $engine->start(); } + public function testDoubleStart() + { + $engine = new Engine(); + $engine->route('/someRoute', function () { + echo 'i ran'; + }, true); + $engine->request()->url = '/someRoute'; + $engine->start(); + + $request = $engine->request(); + $response = $engine->response(); + + // This is pretending like this is embodied in a platform like swoole where + // another request comes in while still holding all the same state. + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/someRoute'; + $engine->start(); + + $this->assertFalse($request === $engine->request()); + $this->assertFalse($response === $engine->response()); + + $this->expectOutputString('i rani ran'); + } + public function testStopWithCode() { $engine = new class extends Engine { diff --git a/tests/FlightTest.php b/tests/FlightTest.php index 54acf53..fbc8eb6 100644 --- a/tests/FlightTest.php +++ b/tests/FlightTest.php @@ -378,7 +378,7 @@ class FlightTest extends TestCase public function testKeepThePreviousStateOfOneViewComponentByDefault(): void { - $this->expectOutputString(<<<'html' + $html = <<<'html'
Hi
Hi
@@ -386,7 +386,12 @@ class FlightTest extends TestCase - html); + html; + + // if windows replace \n with \r\n + $html = str_replace("\n", PHP_EOL, $html); + + $this->expectOutputString($html); Flight::render('myComponent', ['prop' => 'Hi']); Flight::render('myComponent'); diff --git a/tests/RequestTest.php b/tests/RequestTest.php index 03acd5a..4044d06 100644 --- a/tests/RequestTest.php +++ b/tests/RequestTest.php @@ -163,7 +163,7 @@ class RequestTest extends TestCase 'base' => '/vagrant/public', 'query' => new Collection(), 'type' => '', - 'method' => 'GET' + 'method' => 'GET' ]); $this->assertEquals('/flightphp', $request->url); } @@ -174,7 +174,7 @@ class RequestTest extends TestCase 'url' => '', 'base' => '/vagrant/public', 'type' => '', - 'method' => 'GET' + 'method' => 'GET' ]); $this->assertEquals('/', $request->url); } @@ -193,13 +193,13 @@ class RequestTest extends TestCase 'data' => new Collection(), 'query' => new Collection(), 'stream_path' => $stream_path, - 'method' => 'POST' + 'method' => 'POST' ]); $this->assertEquals([ 'foo' => 'bar' ], $request->data->getData()); $this->assertEquals('{"foo":"bar"}', $request->getBody()); } - public function testInitWithFormBody() + public function testInitWithFormBody() { // create dummy file to pull request body from $tmpfile = tmpfile(); @@ -213,12 +213,12 @@ class RequestTest extends TestCase 'data' => new Collection(), 'query' => new Collection(), 'stream_path' => $stream_path, - 'method' => 'PATCH' + 'method' => 'PATCH' ]); - $this->assertEquals([ - 'foo' => 'bar', - 'baz' => 'qux' - ], $request->data->getData()); + $this->assertEquals([ + 'foo' => 'bar', + 'baz' => 'qux' + ], $request->data->getData()); $this->assertEquals('foo=bar&baz=qux', $request->getBody()); } diff --git a/tests/ViewTest.php b/tests/ViewTest.php index e95224d..e6d9d02 100644 --- a/tests/ViewTest.php +++ b/tests/ViewTest.php @@ -175,7 +175,7 @@ class ViewTest extends TestCase public function testKeepThePreviousStateOfOneViewComponentByDefault(): void { - $this->expectOutputString(<<<'html' + $html = <<<'html'
Hi
Hi
@@ -183,7 +183,12 @@ class ViewTest extends TestCase - html); + html; + + // if windows replace \n with \r\n + $html = str_replace("\n", PHP_EOL, $html); + + $this->expectOutputString($html); $this->view->render('myComponent', ['prop' => 'Hi']); $this->view->render('myComponent'); @@ -197,11 +202,16 @@ class ViewTest extends TestCase $this->view->set('prop', 'bar'); - $this->expectOutputString(<<<'html' + $html = <<<'html'
qux
bar
- html); + html; + + // if windows replace \n with \r\n + $html = str_replace("\n", PHP_EOL, $html); + + $this->expectOutputString($html); $this->view->render('myComponent', ['prop' => 'qux']); $this->view->render('myComponent'); @@ -209,24 +219,29 @@ class ViewTest extends TestCase public static function renderDataProvider(): array { - return [ - [ - <<<'html' + $html1 = <<<'html'
Hi
- html, - ['myComponent', ['prop' => 'Hi']], - '/^Undefined variable:? \$?prop$/' - ], - [ - <<<'html' + html; + $html2 = <<<'html' - html, + html; + + $html1 = str_replace("\n", PHP_EOL, $html1); + $html2 = str_replace("\n", PHP_EOL, $html2); + return [ + [ + $html1, + ['myComponent', ['prop' => 'Hi']], + '/^Undefined variable:? \$?prop$/' + ], + [ + $html2, ['input', ['type' => 'number']], '/^.*$/' ], From 7dd52c9ee6dcdba91766bfdfbece1bac3c545b1d Mon Sep 17 00:00:00 2001 From: n0nag0n Date: Thu, 20 Feb 2025 19:31:36 -0700 Subject: [PATCH 2/2] Reset router to beginning --- flight/Engine.php | 2 +- tests/FlightAsyncTest.php | 83 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/FlightAsyncTest.php diff --git a/flight/Engine.php b/flight/Engine.php index e2c1dc3..a26c1ff 100644 --- a/flight/Engine.php +++ b/flight/Engine.php @@ -490,6 +490,7 @@ class Engine $this->unregister('response'); $this->register('request', Request::class); $this->register('response', Response::class); + $this->router()->reset(); } $request = $this->request(); $response = $this->response(); @@ -513,7 +514,6 @@ class Engine // Route the request $failedMiddlewareCheck = false; - while ($route = $router->route($request)) { $params = array_values($route->params); diff --git a/tests/FlightAsyncTest.php b/tests/FlightAsyncTest.php new file mode 100644 index 0000000..1a53f44 --- /dev/null +++ b/tests/FlightAsyncTest.php @@ -0,0 +1,83 @@ +expectOutputString('hello world'); + Flight::start(); + } + + public function testMultipleRoutes() + { + Flight::route('GET /', function () { + echo 'hello world'; + }); + + Flight::route('GET /test', function () { + echo 'test'; + }); + + $this->expectOutputString('test'); + $_SERVER['REQUEST_URI'] = '/test'; + Flight::start(); + } + + public function testMultipleStartsSingleRoute() + { + Flight::route('GET /', function () { + echo 'hello world'; + }); + + $this->expectOutputString('hello worldhello world'); + Flight::start(); + Flight::start(); + } + + public function testMultipleStartsMultipleRoutes() + { + Flight::route('GET /', function () { + echo 'hello world'; + }); + + Flight::route('GET /test', function () { + echo 'test'; + }); + + $this->expectOutputString('testhello world'); + $_SERVER['REQUEST_URI'] = '/test'; + Flight::start(); + $_SERVER['REQUEST_URI'] = '/'; + Flight::start(); + } +}