diff --git a/flight/Engine.php b/flight/Engine.php
index 7b65e92..4b1bdca 100644
--- a/flight/Engine.php
+++ b/flight/Engine.php
@@ -30,7 +30,14 @@ use Throwable;
* @method void start() Starts engine
* @method void stop() Stops framework and outputs current response
* @method void halt(int $code = 200, string $message = '') Stops processing and returns a given response.
+ *
+ * Routing
* @method void route(string $pattern, callable $callback, bool $pass_route = false) Routes a URL to a callback function.
+ * @method void get(string $pattern, callable $callback, bool $pass_route = false) Routes a GET URL to a callback function.
+ * @method void post(string $pattern, callable $callback, bool $pass_route = false) Routes a POST URL to a callback function.
+ * @method void put(string $pattern, callable $callback, bool $pass_route = false) Routes a PUT URL to a callback function.
+ * @method void patch(string $pattern, callable $callback, bool $pass_route = false) Routes a PATCH URL to a callback function.
+ * @method void delete(string $pattern, callable $callback, bool $pass_route = false) Routes a DELETE URL to a callback function.
* @method Router router() Gets router
*
* Views
@@ -68,6 +75,13 @@ class Engine
*/
protected Dispatcher $dispatcher;
+ /**
+ * If the framework has been initialized or not
+ *
+ * @var boolean
+ */
+ protected bool $initialized = false;
+
/**
* Constructor.
*/
@@ -115,7 +129,7 @@ class Engine
*/
public function init(): void
{
- static $initialized = false;
+ $initialized = $this->initialized;
$self = $this;
if ($initialized) {
@@ -166,7 +180,7 @@ class Engine
$self->response()->content_length = $self->get('flight.content_length');
});
- $initialized = true;
+ $this->initialized = true;
}
/**
@@ -197,7 +211,7 @@ class Engine
public function handleException($e): void
{
if ($this->get('flight.log_errors')) {
- error_log($e->getMessage());
+ error_log($e->getMessage()); // @codeCoverageIgnore
}
$this->error($e);
@@ -353,7 +367,7 @@ class Engine
// Flush any existing output
if (ob_get_length() > 0) {
- $response->write(ob_get_clean());
+ $response->write(ob_get_clean()); // @codeCoverageIgnore
}
// Enable output buffering
@@ -412,9 +426,11 @@ class Engine
->status(500)
->write($msg)
->send();
+ // @codeCoverageIgnoreStart
} catch (Throwable $t) {
exit($msg);
}
+ // @codeCoverageIgnoreEnd
}
/**
@@ -505,6 +521,7 @@ class Engine
*
* @param int $code HTTP status code
* @param string $message Response message
+ *
*/
public function _halt(int $code = 200, string $message = ''): void
{
@@ -513,7 +530,10 @@ class Engine
->status($code)
->write($message)
->send();
- exit();
+ // apologies for the crappy hack here...
+ if($message !== 'skip---exit') {
+ exit(); // @codeCoverageIgnore
+ }
}
/**
diff --git a/flight/template/View.php b/flight/template/View.php
index 6796577..818a100 100644
--- a/flight/template/View.php
+++ b/flight/template/View.php
@@ -186,11 +186,13 @@ class View
$file .= $ext;
}
- if (('/' == substr($file, 0, 1))) {
+ $is_windows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
+
+ if (('/' == substr($file, 0, 1)) || ($is_windows === true && ':' == substr($file, 1, 1))) {
return $file;
}
- return $this->path . '/' . $file;
+ return $this->path . DIRECTORY_SEPARATOR . $file;
}
/**
diff --git a/tests/EngineTest.php b/tests/EngineTest.php
new file mode 100644
index 0000000..33464f3
--- /dev/null
+++ b/tests/EngineTest.php
@@ -0,0 +1,188 @@
+
+ * @license MIT, http://flightphp.com/license
+ */
+
+
+class EngineTest extends PHPUnit\Framework\TestCase
+{
+ public function setUp(): void {
+ $_SERVER = [];
+ }
+
+ public function tearDown(): void {
+ $_SERVER = [];
+ }
+ public function testInitBeforeStart() {
+ $engine = new class extends Engine {
+ public function getInitializedVar() {
+ return $this->initialized;
+ }
+ };
+ $this->assertTrue($engine->getInitializedVar());
+ $engine->start();
+
+ // this is necessary cause it doesn't actually send the response correctly
+ ob_end_clean();
+
+ $this->assertFalse($engine->router()->case_sensitive);
+ $this->assertTrue($engine->response()->content_length);
+ }
+
+ public function testHandleErrorNoErrorNumber() {
+ $engine = new Engine();
+ $result = $engine->handleError(0, '', '', 0);
+ $this->assertFalse($result);
+ }
+
+ public function testHandleErrorWithException() {
+ $engine = new Engine();
+ $this->expectException(Exception::class);
+ $this->expectExceptionCode(5);
+ $this->expectExceptionMessage('thrown error message');
+ $engine->handleError(5, 'thrown error message', '', 0);
+ }
+
+ public function testHandleException() {
+ $engine = new Engine();
+ $regex_message = preg_quote('
500 Internal Server Error
thrown exception message (20)
');
+ $this->expectOutputRegex('~'.$regex_message.'~');
+ $engine->handleException(new Exception('thrown exception message', 20));
+ }
+
+ public function testMapExistingMethod() {
+ $engine = new Engine();
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Cannot override an existing framework method.');
+ $engine->map('_start', function() {});
+ }
+
+ public function testRegisterExistingMethod() {
+ $engine = new Engine();
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Cannot override an existing framework method.');
+ $engine->register('_error', 'stdClass');
+ }
+
+ public function testSetArrayOfValues() {
+ $engine = new Engine();
+ $engine->set([ 'key1' => 'value1', 'key2' => 'value2']);
+ $this->assertEquals('value1', $engine->get('key1'));
+ $this->assertEquals('value2', $engine->get('key2'));
+ }
+
+ public function testStartWithRoute() {
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $_SERVER['REQUEST_URI'] = '/someRoute';
+
+ $engine = new class extends Engine {
+ public function getInitializedVar() {
+ return $this->initialized;
+ }
+ };
+ $engine->route('/someRoute', function() { echo 'i ran'; }, true);
+ $this->expectOutputString('i ran');
+ $engine->start();
+ }
+
+ // n0nag0n - I don't know why this does what it does, but it's existing framework functionality 1/1/24
+ public function testStartWithRouteButReturnedValueThrows404() {
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $_SERVER['REQUEST_URI'] = '/someRoute';
+
+ $engine = new class extends Engine {
+ public function getInitializedVar() {
+ return $this->initialized;
+ }
+ };
+ $engine->route('/someRoute', function() { echo 'i ran'; return true; }, true);
+ $this->expectOutputString('404 Not Found
The page you have requested could not be found.
');
+ $engine->start();
+ }
+
+ public function testStopWithCode() {
+ $engine = new class extends Engine {
+ public function getLoader() {
+ return $this->loader;
+ }
+ };
+ // doing this so we can overwrite some parts of the response
+ $engine->getLoader()->register('response', function() {
+ return new class extends \flight\net\Response {
+ public function __construct() {}
+ public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response
+ {
+ return $this;
+ }
+ };
+ });
+ // need to add another one of these because _stop() stops and gets clean, but $response->send() does too.....
+ ob_start();
+ $engine->response()->write('I am a teapot');
+ $this->expectOutputString('I am a teapot');
+ $engine->stop(500);
+ $this->assertEquals(500, $engine->response()->status());
+ }
+
+ public function testPostRoute() {
+ $engine = new Engine();
+ $engine->post('/someRoute', function() { echo 'i ran'; }, true);
+ $routes = $engine->router()->getRoutes();
+ $this->assertEquals('POST', $routes[0]->methods[0]);
+ $this->assertEquals('/someRoute', $routes[0]->pattern);
+ }
+
+ public function testPutRoute() {
+ $engine = new Engine();
+ $engine->put('/someRoute', function() { echo 'i ran'; }, true);
+ $routes = $engine->router()->getRoutes();
+ $this->assertEquals('PUT', $routes[0]->methods[0]);
+ $this->assertEquals('/someRoute', $routes[0]->pattern);
+ }
+
+ public function testPatchRoute() {
+ $engine = new Engine();
+ $engine->patch('/someRoute', function() { echo 'i ran'; }, true);
+ $routes = $engine->router()->getRoutes();
+ $this->assertEquals('PATCH', $routes[0]->methods[0]);
+ $this->assertEquals('/someRoute', $routes[0]->pattern);
+ }
+
+ public function testDeleteRoute() {
+ $engine = new Engine();
+ $engine->delete('/someRoute', function() { echo 'i ran'; }, true);
+ $routes = $engine->router()->getRoutes();
+ $this->assertEquals('DELETE', $routes[0]->methods[0]);
+ $this->assertEquals('/someRoute', $routes[0]->pattern);
+ }
+
+ public function testHalt() {
+ $engine = new class extends Engine {
+ public function getLoader() {
+ return $this->loader;
+ }
+ };
+ // doing this so we can overwrite some parts of the response
+ $engine->getLoader()->register('response', function() {
+ return new class extends \flight\net\Response {
+ public function __construct() {}
+ public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response
+ {
+ return $this;
+ }
+ };
+ });
+ // need to add another one of these because _stop() stops and gets clean, but $response->send() does too.....
+ //ob_start();
+ $this->expectOutputString('skip---exit');
+ $engine->halt(500, 'skip---exit');
+ $this->assertEquals(500, $engine->response()->status());
+ }
+}
diff --git a/tests/ViewTest.php b/tests/ViewTest.php
index c952b50..2013861 100644
--- a/tests/ViewTest.php
+++ b/tests/ViewTest.php
@@ -101,7 +101,8 @@ class ViewTest extends PHPUnit\Framework\TestCase
public function testGetTemplateAbsolutePath() {
$tmpfile = tmpfile();
- $file_path = stream_get_meta_data($tmpfile)['uri'].'.php';
+ $this->view->extension = '';
+ $file_path = stream_get_meta_data($tmpfile)['uri'];
$this->assertEquals($file_path, $this->view->getTemplate($file_path));
}