added PSR12 coding style to files.

pull/529/head
Austin Collier 1 year ago
parent 0d7b79bab9
commit cc4338a34b

@ -37,7 +37,8 @@
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^1.10",
"phpstan/extension-installer": "^1.3",
"rregeer/phpunit-coverage-check": "^0.3.1"
"rregeer/phpunit-coverage-check": "^0.3.1",
"squizlabs/php_codesniffer": "^3.8"
},
"config": {
"allow-plugins": {
@ -47,7 +48,9 @@
"scripts": {
"test": "phpunit",
"test-coverage": "XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html=coverage --coverage-clover=clover.xml && vendor/bin/coverage-check clover.xml 100",
"lint": "phpstan --no-progress -cphpstan.neon"
"lint": "phpstan --no-progress -cphpstan.neon",
"beautify": "phpcbf --standard=phpcs.xml",
"phpcs": "phpcs --standard=phpcs.xml"
},
"suggest": {
"latte/latte": "Latte template engine",

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -32,7 +33,7 @@ use flight\net\Route;
* @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 Route route(string $pattern, callable $callback, bool $pass_route = false, string $alias = '') Routes a URL to a callback function with all applicable methods
* @method void group(string $pattern, callable $callback, array $group_middlewares = []) Groups a set of routes together under a common prefix.
@ -78,12 +79,12 @@ class Engine
*/
protected Dispatcher $dispatcher;
/**
* If the framework has been initialized or not
*
* @var boolean
*/
protected bool $initialized = false;
/**
* If the framework has been initialized or not
*
* @var boolean
*/
protected bool $initialized = false;
/**
* Constructor.
@ -377,7 +378,7 @@ class Engine
ob_start();
// Route the request
$failed_middleware_check = false;
$failed_middleware_check = false;
while ($route = $router->route($request)) {
$params = array_values($route->params);
@ -386,55 +387,52 @@ class Engine
$params[] = $route;
}
// Run any before middlewares
if(count($route->middleware) > 0) {
foreach($route->middleware as $middleware) {
$middleware_object = (is_callable($middleware) === true ? $middleware : (method_exists($middleware, 'before') === true ? [ $middleware, 'before' ]: false));
// Run any before middlewares
if (count($route->middleware) > 0) {
foreach ($route->middleware as $middleware) {
$middleware_object = (is_callable($middleware) === true ? $middleware : (method_exists($middleware, 'before') === true ? [ $middleware, 'before' ] : false));
if($middleware_object === false) {
continue;
}
if ($middleware_object === false) {
continue;
}
// It's assumed if you don't declare before, that it will be assumed as the before method
$middleware_result = $middleware_object($route->params);
// It's assumed if you don't declare before, that it will be assumed as the before method
$middleware_result = $middleware_object($route->params);
if ($middleware_result === false) {
$failed_middleware_check = true;
break 2;
}
}
}
if ($middleware_result === false) {
$failed_middleware_check = true;
break 2;
}
}
}
// Call route handler
$continue = $this->dispatcher->execute(
$route->callback,
$params
);
// Run any before middlewares
if(count($route->middleware) > 0) {
// process the middleware in reverse order now
foreach(array_reverse($route->middleware) as $middleware) {
// must be an object. No functions allowed here
$middleware_object = is_object($middleware) === true && !($middleware instanceof Closure) && method_exists($middleware, 'after') === true ? [ $middleware, 'after' ] : false;
// Run any before middlewares
if (count($route->middleware) > 0) {
// process the middleware in reverse order now
foreach (array_reverse($route->middleware) as $middleware) {
// must be an object. No functions allowed here
$middleware_object = is_object($middleware) === true && !($middleware instanceof Closure) && method_exists($middleware, 'after') === true ? [ $middleware, 'after' ] : false;
// has to have the after method, otherwise just skip it
if($middleware_object === false) {
continue;
}
// has to have the after method, otherwise just skip it
if ($middleware_object === false) {
continue;
}
$middleware_result = $middleware_object($route->params);
$middleware_result = $middleware_object($route->params);
if ($middleware_result === false) {
$failed_middleware_check = true;
break 2;
}
}
}
if ($middleware_result === false) {
$failed_middleware_check = true;
break 2;
}
}
}
$dispatched = true;
@ -447,9 +445,9 @@ class Engine
$dispatched = false;
}
if($failed_middleware_check === true) {
$this->halt(403, 'Forbidden');
} else if($dispatched === false) {
if ($failed_middleware_check === true) {
$this->halt(403, 'Forbidden');
} elseif ($dispatched === false) {
$this->notFound();
}
}
@ -476,11 +474,11 @@ class Engine
->status(500)
->write($msg)
->send();
// @codeCoverageIgnoreStart
// @codeCoverageIgnoreStart
} catch (Throwable $t) {
exit($msg);
}
// @codeCoverageIgnoreEnd
// @codeCoverageIgnoreEnd
}
/**
@ -512,20 +510,20 @@ class Engine
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias the alias for the route
* @return Route
* @param string $alias the alias for the route
* @return Route
*/
public function _route(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route
{
return $this->router()->map($pattern, $callback, $pass_route, $alias);
}
/**
/**
* Routes a URL to a callback function.
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function that includes the Router class as first parameter
* @param array<callable> $group_middlewares The middleware to be applied to the route
* @param string $pattern URL pattern to match
* @param callable $callback Callback function that includes the Router class as first parameter
* @param array<callable> $group_middlewares The middleware to be applied to the route
*/
public function _group(string $pattern, callable $callback, array $group_middlewares = []): void
{
@ -585,7 +583,7 @@ class Engine
*
* @param int $code HTTP status code
* @param string $message Response message
*
*
*/
public function _halt(int $code = 200, string $message = ''): void
{
@ -594,10 +592,10 @@ class Engine
->status($code)
->write($message)
->send();
// apologies for the crappy hack here...
if($message !== 'skip---exit') {
exit(); // @codeCoverageIgnore
}
// apologies for the crappy hack here...
if ($message !== 'skip---exit') {
exit(); // @codeCoverageIgnore
}
}
/**
@ -728,7 +726,7 @@ class Engine
{
$id = (('weak' === $type) ? 'W/' : '') . $id;
$this->response()->header('ETag', '"'.str_replace('"', '\"', $id).'"');
$this->response()->header('ETag', '"' . str_replace('"', '\"', $id) . '"');
if (
isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
@ -755,14 +753,14 @@ class Engine
}
}
/**
* Gets a url from an alias that's supplied.
*
* @param string $alias the route alias.
* @param array<string, mixed> $params The params for the route if applicable.
*/
public function _getUrl(string $alias, array $params = []): string
{
return $this->router()->getUrlByAlias($alias, $params);
}
/**
* Gets a url from an alias that's supplied.
*
* @param string $alias the route alias.
* @param array<string, mixed> $params The params for the route if applicable.
*/
public function _getUrl(string $alias, array $params = []): string
{
return $this->router()->getUrlByAlias($alias, $params);
}
}

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -61,34 +62,34 @@ class Flight
{
/**
* Framework engine.
*
* @var Engine $engine
*
* @var Engine $engine
*/
private static Engine $engine;
/**
* Whether or not the app has been initialized
*
* @var boolean
*/
private static bool $initialized = false;
/**
* Whether or not the app has been initialized
*
* @var boolean
*/
private static bool $initialized = false;
/**
* Don't allow object instantiation
*
* @codeCoverageIgnore
* @return void
*/
/**
* Don't allow object instantiation
*
* @codeCoverageIgnore
* @return void
*/
private function __construct()
{
}
/**
* Forbid cloning the class
*
* @codeCoverageIgnore
* @return void
*/
/**
* Forbid cloning the class
*
* @codeCoverageIgnore
* @return void
*/
private function __clone()
{
}
@ -145,14 +146,14 @@ class Flight
return self::$engine;
}
/**
* Set the engine instance
*
* @param Engine $engine Vroom vroom!
* @return void
*/
public static function setEngine(Engine $engine): void
{
self::$engine = $engine;
}
/**
* Set the engine instance
*
* @param Engine $engine Vroom vroom!
* @return void
*/
public static function setEngine(Engine $engine): void
{
self::$engine = $engine;
}
}

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -53,7 +54,7 @@ class Dispatcher
}
// Run requested method
$callback = $this->get($name);
$callback = $this->get($name);
$output = $callback(...$params);
// Run post-filters
@ -178,7 +179,7 @@ class Dispatcher
*/
public static function callFunction($func, array &$params = [])
{
return call_user_func_array($func, $params);
return call_user_func_array($func, $params);
}
/**
@ -195,9 +196,9 @@ class Dispatcher
$instance = \is_object($class);
return ($instance) ?
$class->$method(...$params) :
$class::$method();
return ($instance) ?
$class->$method(...$params) :
$class::$method();
}
/**

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -134,7 +135,7 @@ class Loader
return \call_user_func_array($class, $params);
}
return new $class(...$params);
return new $class(...$params);
}
/**
@ -179,8 +180,8 @@ class Loader
/**
* Autoloads classes.
*
* Classes are not allowed to have underscores in their names.
*
* Classes are not allowed to have underscores in their names.
*
* @param string $class Class name
*/

@ -5,144 +5,149 @@ namespace flight\database;
use PDO;
use PDOStatement;
class PdoWrapper extends PDO {
/**
* How you create the connection for the database
*
* @param string $dsn - Ex: 'mysql:host=localhost;port=3306;dbname=testdb;charset=utf8mb4'
* @param string $username - Ex: 'root'
* @param string $password - Ex: 'password'
* @param array<int,mixed> $options - PDO options you can pass in
*/
public function __construct(string $dsn, ?string $username = null, ?string $password = null, array $options = []) {
parent::__construct($dsn, $username, $password, $options);
}
/**
* Use this for INSERTS, UPDATES, or if you plan on using a SELECT in a while loop
*
* Ex: $statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]);
* while($row = $statement->fetch()) {
* // ...
* }
*
* $db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]);
* $db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);
*
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return PDOStatement
*/
public function runQuery(string $sql, array $params = []): PDOStatement {
$processed_sql_data = $this->processInStatementSql($sql, $params);
$sql = $processed_sql_data['sql'];
$params = $processed_sql_data['params'];
$statement = $this->prepare($sql);
$statement->execute($params);
return $statement;
}
/**
* Pulls one field from the query
*
* Ex: $id = $db->fetchField("SELECT id FROM table WHERE something = ?", [ $something ]);
*
* @param string $sql - Ex: "SELECT id FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return mixed
*/
public function fetchField(string $sql, array $params = []) {
$data = $this->fetchRow($sql, $params);
return reset($data);
}
/**
* Pulls one row from the query
*
* Ex: $row = $db->fetchRow("SELECT * FROM table WHERE something = ?", [ $something ]);
*
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return array<string,mixed>
*/
public function fetchRow(string $sql, array $params = []): array {
$sql .= stripos($sql, 'LIMIT') === false ? ' LIMIT 1' : '';
$result = $this->fetchAll($sql, $params);
return count($result) > 0 ? $result[0] : [];
}
/**
* Pulls all rows from the query
*
* Ex: $rows = $db->fetchAll("SELECT * FROM table WHERE something = ?", [ $something ]);
* foreach($rows as $row) {
* // ...
* }
*
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return array<int,array<string,mixed>>
*/
public function fetchAll(string $sql, array $params = []): array {
$processed_sql_data = $this->processInStatementSql($sql, $params);
$sql = $processed_sql_data['sql'];
$params = $processed_sql_data['params'];
$statement = $this->prepare($sql);
$statement->execute($params);
$result = $statement->fetchAll();
return is_array($result) ? $result : [];
}
/**
* Don't worry about this guy. Converts stuff for IN statements
*
* Ex: $row = $db->fetchAll("SELECT * FROM table WHERE id = ? AND something IN(?), [ $id, [1,2,3] ]);
* Converts this to "SELECT * FROM table WHERE id = ? AND something IN(?,?,?)"
*
* @param string $sql the sql statement
* @param array<int|string,mixed> $params the params for the sql statement
* @return array<string,string|array<int|string,mixed>>
*/
protected function processInStatementSql(string $sql, array $params = []): array {
// Handle "IN(?)". This is to be used with a comma delimited string, but can also be used with an array.
// Remove the spaces in variations of "IN ( ? )" where the space after IN is optional, and any number of spaces before and after the question mark is optional.
// Then loop through each "IN(?)" in the query and replace the single question mark with the correct number of question marks.
$sql = preg_replace('/IN\s*\(\s*\?\s*\)/i', 'IN(?)', $sql);
$current_index = 0;
while(($current_index = strpos($sql, 'IN(?)', $current_index)) !== false) {
$preceeding_count = substr_count($sql, '?', 0, $current_index - 1);
$param = $params[$preceeding_count];
$question_marks = '?';
// If param is a string, explode it and replace the question mark with the correct number of question marks
if(is_string($param) || is_array($param)) {
$params_to_use = $param;
if(is_string($param)) {
$params_to_use = explode(',', $param);
}
foreach($params_to_use as $key => $value) {
if(is_string($value)) {
$params_to_use[$key] = trim($value);
}
}
// Replace the single question mark with the appropriate number of question marks.
$question_marks = join(',', array_fill(0, count($params_to_use), '?'));
$sql = substr_replace($sql, $question_marks, $current_index + 3, 1);
// Insert the new params into the params array.
array_splice($params, $preceeding_count, 1, $params_to_use);
}
// Increment by the length of the question marks and accounting for the length of "IN()"
$current_index += strlen($question_marks) + 4;
}
return [ 'sql' => $sql, 'params' => $params ];
}
}
class PdoWrapper extends PDO
{
/**
* How you create the connection for the database
*
* @param string $dsn - Ex: 'mysql:host=localhost;port=3306;dbname=testdb;charset=utf8mb4'
* @param string $username - Ex: 'root'
* @param string $password - Ex: 'password'
* @param array<int,mixed> $options - PDO options you can pass in
*/
public function __construct(string $dsn, ?string $username = null, ?string $password = null, array $options = [])
{
parent::__construct($dsn, $username, $password, $options);
}
/**
* Use this for INSERTS, UPDATES, or if you plan on using a SELECT in a while loop
*
* Ex: $statement = $db->runQuery("SELECT * FROM table WHERE something = ?", [ $something ]);
* while($row = $statement->fetch()) {
* // ...
* }
*
* $db->runQuery("INSERT INTO table (name) VALUES (?)", [ $name ]);
* $db->runQuery("UPDATE table SET name = ? WHERE id = ?", [ $name, $id ]);
*
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return PDOStatement
*/
public function runQuery(string $sql, array $params = []): PDOStatement
{
$processed_sql_data = $this->processInStatementSql($sql, $params);
$sql = $processed_sql_data['sql'];
$params = $processed_sql_data['params'];
$statement = $this->prepare($sql);
$statement->execute($params);
return $statement;
}
/**
* Pulls one field from the query
*
* Ex: $id = $db->fetchField("SELECT id FROM table WHERE something = ?", [ $something ]);
*
* @param string $sql - Ex: "SELECT id FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return mixed
*/
public function fetchField(string $sql, array $params = [])
{
$data = $this->fetchRow($sql, $params);
return reset($data);
}
/**
* Pulls one row from the query
*
* Ex: $row = $db->fetchRow("SELECT * FROM table WHERE something = ?", [ $something ]);
*
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return array<string,mixed>
*/
public function fetchRow(string $sql, array $params = []): array
{
$sql .= stripos($sql, 'LIMIT') === false ? ' LIMIT 1' : '';
$result = $this->fetchAll($sql, $params);
return count($result) > 0 ? $result[0] : [];
}
/**
* Pulls all rows from the query
*
* Ex: $rows = $db->fetchAll("SELECT * FROM table WHERE something = ?", [ $something ]);
* foreach($rows as $row) {
* // ...
* }
*
* @param string $sql - Ex: "SELECT * FROM table WHERE something = ?"
* @param array<int|string,mixed> $params - Ex: [ $something ]
* @return array<int,array<string,mixed>>
*/
public function fetchAll(string $sql, array $params = []): array
{
$processed_sql_data = $this->processInStatementSql($sql, $params);
$sql = $processed_sql_data['sql'];
$params = $processed_sql_data['params'];
$statement = $this->prepare($sql);
$statement->execute($params);
$result = $statement->fetchAll();
return is_array($result) ? $result : [];
}
/**
* Don't worry about this guy. Converts stuff for IN statements
*
* Ex: $row = $db->fetchAll("SELECT * FROM table WHERE id = ? AND something IN(?), [ $id, [1,2,3] ]);
* Converts this to "SELECT * FROM table WHERE id = ? AND something IN(?,?,?)"
*
* @param string $sql the sql statement
* @param array<int|string,mixed> $params the params for the sql statement
* @return array<string,string|array<int|string,mixed>>
*/
protected function processInStatementSql(string $sql, array $params = []): array
{
// Handle "IN(?)". This is to be used with a comma delimited string, but can also be used with an array.
// Remove the spaces in variations of "IN ( ? )" where the space after IN is optional, and any number of spaces before and after the question mark is optional.
// Then loop through each "IN(?)" in the query and replace the single question mark with the correct number of question marks.
$sql = preg_replace('/IN\s*\(\s*\?\s*\)/i', 'IN(?)', $sql);
$current_index = 0;
while (($current_index = strpos($sql, 'IN(?)', $current_index)) !== false) {
$preceeding_count = substr_count($sql, '?', 0, $current_index - 1);
$param = $params[$preceeding_count];
$question_marks = '?';
// If param is a string, explode it and replace the question mark with the correct number of question marks
if (is_string($param) || is_array($param)) {
$params_to_use = $param;
if (is_string($param)) {
$params_to_use = explode(',', $param);
}
foreach ($params_to_use as $key => $value) {
if (is_string($value)) {
$params_to_use[$key] = trim($value);
}
}
// Replace the single question mark with the appropriate number of question marks.
$question_marks = join(',', array_fill(0, count($params_to_use), '?'));
$sql = substr_replace($sql, $question_marks, $current_index + 3, 1);
// Insert the new params into the params array.
array_splice($params, $preceeding_count, 1, $params_to_use);
}
// Increment by the length of the question marks and accounting for the length of "IN()"
$current_index += strlen($question_marks) + 4;
}
return [ 'sql' => $sql, 'params' => $params ];
}
}

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -187,9 +188,9 @@ class Request
}
// Get the requested URL without the base directory
// This rewrites the url in case the public url and base directories match
// (such as installing on a subdirectory in a web server)
// @see testInitUrlSameAsBaseDirectory
// This rewrites the url in case the public url and base directories match
// (such as installing on a subdirectory in a web server)
// @see testInitUrlSameAsBaseDirectory
if ('/' !== $this->base && '' !== $this->base && 0 === strpos($this->url, $this->base)) {
$this->url = substr($this->url, \strlen($this->base));
}

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -237,7 +238,7 @@ class Response
{
// Send status code header
if (false !== strpos(\PHP_SAPI, 'cgi')) {
// @codeCoverageIgnoreStart
// @codeCoverageIgnoreStart
$this->setRealHeader(
sprintf(
'Status: %d %s',
@ -246,7 +247,7 @@ class Response
),
true
);
// @codeCoverageIgnoreEnd
// @codeCoverageIgnoreEnd
} else {
$this->setRealHeader(
sprintf(
@ -283,19 +284,20 @@ class Response
return $this;
}
/**
* Sets a real header. Mostly used for test mocking.
*
* @param string $header_string The header string you would pass to header()
* @param bool $replace The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header of the same type. By default it will replace, but if you pass in false as the second argument you can force multiple headers of the same type.
* @param int $response_code The response code to send
* @return $this
* @codeCoverageIgnore
*/
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): self {
header($header_string, $replace, $response_code);
return $this;
}
/**
* Sets a real header. Mostly used for test mocking.
*
* @param string $header_string The header string you would pass to header()
* @param bool $replace The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header of the same type. By default it will replace, but if you pass in false as the second argument you can force multiple headers of the same type.
* @param int $response_code The response code to send
* @return $this
* @codeCoverageIgnore
*/
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): self
{
header($header_string, $replace, $response_code);
return $this;
}
/**
* Gets the content length.

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -52,15 +53,15 @@ class Route
*/
public bool $pass = false;
/**
* The alias is a way to identify the route using a simple name ex: 'login' instead of /admin/login
*/
public string $alias = '';
/**
* The alias is a way to identify the route using a simple name ex: 'login' instead of /admin/login
*/
public string $alias = '';
/**
* @var array<int,callable|object> The middleware to be applied to the route
*/
public array $middleware = [];
/**
* @var array<int,callable|object> The middleware to be applied to the route
*/
public array $middleware = [];
/**
* Constructor.
@ -76,7 +77,7 @@ class Route
$this->callback = $callback;
$this->methods = $methods;
$this->pass = $pass;
$this->alias = $alias;
$this->alias = $alias;
}
/**
@ -165,55 +166,58 @@ class Route
return \count(array_intersect([$method, '*'], $this->methods)) > 0;
}
/**
* Checks if an alias matches the route alias.
*/
public function matchAlias(string $alias): bool
{
return $this->alias === $alias;
}
/**
* Hydrates the route url with the given parameters
*
* @param array<string,mixed> $params the parameters to pass to the route
*/
public function hydrateUrl(array $params = []): string {
$url = preg_replace_callback("/(?:@([a-zA-Z0-9]+)(?:\:([^\/]+))?\)*)/i", function($match) use ($params) {
if(isset($match[1]) && isset($params[$match[1]])) {
return $params[$match[1]];
}
}, $this->pattern);
// catches potential optional parameter
$url = str_replace('(/', '/', $url);
// trim any trailing slashes
$url = rtrim($url, '/');
return $url;
}
/**
* Sets the route alias
*
* @return $this
*/
public function setAlias(string $alias): self {
$this->alias = $alias;
return $this;
}
/**
* Sets the route middleware
*
* @param array<int, callable>|callable $middleware
* @return $this
*/
public function addMiddleware($middleware): self {
if(is_array($middleware) === true) {
$this->middleware = array_merge($this->middleware, $middleware);
} else {
$this->middleware[] = $middleware;
}
return $this;
}
/**
* Checks if an alias matches the route alias.
*/
public function matchAlias(string $alias): bool
{
return $this->alias === $alias;
}
/**
* Hydrates the route url with the given parameters
*
* @param array<string,mixed> $params the parameters to pass to the route
*/
public function hydrateUrl(array $params = []): string
{
$url = preg_replace_callback("/(?:@([a-zA-Z0-9]+)(?:\:([^\/]+))?\)*)/i", function ($match) use ($params) {
if (isset($match[1]) && isset($params[$match[1]])) {
return $params[$match[1]];
}
}, $this->pattern);
// catches potential optional parameter
$url = str_replace('(/', '/', $url);
// trim any trailing slashes
$url = rtrim($url, '/');
return $url;
}
/**
* Sets the route alias
*
* @return $this
*/
public function setAlias(string $alias): self
{
$this->alias = $alias;
return $this;
}
/**
* Sets the route middleware
*
* @param array<int, callable>|callable $middleware
* @return $this
*/
public function addMiddleware($middleware): self
{
if (is_array($middleware) === true) {
$this->middleware = array_merge($this->middleware, $middleware);
} else {
$this->middleware[] = $middleware;
}
return $this;
}
}

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -34,17 +35,17 @@ class Router
*/
protected int $index = 0;
/**
* When groups are used, this is mapped against all the routes
*/
protected string $group_prefix = '';
/**
* When groups are used, this is mapped against all the routes
*/
protected string $group_prefix = '';
/**
* Group Middleware
*
* @var array<int,mixed>
*/
protected array $group_middlewares = [];
/**
* Group Middleware
*
* @var array<int,mixed>
*/
protected array $group_middlewares = [];
/**
* Gets mapped routes.
@ -70,7 +71,7 @@ class Router
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $route_alias Alias for the route
* @param string $route_alias Alias for the route
*/
public function map(string $pattern, callable $callback, bool $pass_route = false, string $route_alias = ''): Route
{
@ -83,94 +84,100 @@ class Router
$methods = explode('|', $method);
}
$route = new Route($this->group_prefix.$url, $callback, $methods, $pass_route, $route_alias);
$route = new Route($this->group_prefix . $url, $callback, $methods, $pass_route, $route_alias);
// to handle group middleware
foreach($this->group_middlewares as $gm) {
$route->addMiddleware($gm);
}
// to handle group middleware
foreach ($this->group_middlewares as $gm) {
$route->addMiddleware($gm);
}
$this->routes[] = $route;
return $route;
return $route;
}
/**
* Creates a GET based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function get(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route
{
return $this->map('GET ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a POST based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function post(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route
{
return $this->map('POST ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a PUT based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function put(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route
{
return $this->map('PUT ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a PATCH based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route
{
return $this->map('PATCH ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a GET based route
*
* @param string $pattern URL pattern to match
/**
* Creates a DELETE based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function get(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route {
return $this->map('GET ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a POST based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function post(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route {
return $this->map('POST ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a PUT based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function put(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route {
return $this->map('PUT ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a PATCH based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function patch(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route {
return $this->map('PATCH ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Creates a DELETE based route
*
* @param string $pattern URL pattern to match
* @param callable $callback Callback function
* @param bool $pass_route Pass the matching route object to the callback
* @param string $alias Alias for the route
*/
public function delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route {
return $this->map('DELETE ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Group together a set of routes
*
* @param string $group_prefix group URL prefix (such as /api/v1)
* @param callable $callback The necessary calling that holds the Router class
* @param array<int,callable|object> $group_middlewares The middlewares to be applied to the group Ex: [ $middleware1, $middleware2 ]
*/
public function group(string $group_prefix, callable $callback, array $group_middlewares = []): void {
$old_group_prefix = $this->group_prefix;
$old_group_middlewares = $this->group_middlewares;
$this->group_prefix .= $group_prefix;
$this->group_middlewares = array_merge($this->group_middlewares, $group_middlewares);
$callback($this);
$this->group_prefix = $old_group_prefix;
$this->group_middlewares = $old_group_middlewares;
}
* @param string $alias Alias for the route
*/
public function delete(string $pattern, callable $callback, bool $pass_route = false, string $alias = ''): Route
{
return $this->map('DELETE ' . $pattern, $callback, $pass_route, $alias);
}
/**
* Group together a set of routes
*
* @param string $group_prefix group URL prefix (such as /api/v1)
* @param callable $callback The necessary calling that holds the Router class
* @param array<int,callable|object> $group_middlewares The middlewares to be applied to the group Ex: [ $middleware1, $middleware2 ]
*/
public function group(string $group_prefix, callable $callback, array $group_middlewares = []): void
{
$old_group_prefix = $this->group_prefix;
$old_group_middlewares = $this->group_middlewares;
$this->group_prefix .= $group_prefix;
$this->group_middlewares = array_merge($this->group_middlewares, $group_middlewares);
$callback($this);
$this->group_prefix = $old_group_prefix;
$this->group_middlewares = $old_group_middlewares;
}
/**
* Routes the current request.
@ -190,58 +197,58 @@ class Router
return false;
}
/**
* Gets the URL for a given route alias
*
* @param string $alias the alias to match
* @param array<string,mixed> $params the parameters to pass to the route
*/
public function getUrlByAlias(string $alias, array $params = []): string {
$potential_aliases = [];
foreach($this->routes as $route) {
$potential_aliases[] = $route->alias;
if ($route->matchAlias($alias)) {
return $route->hydrateUrl($params);
}
}
// use a levenshtein to find the closest match and make a recommendation
$closest_match = '';
$closest_match_distance = 0;
foreach($potential_aliases as $potential_alias) {
$levenshtein_distance = levenshtein($alias, $potential_alias);
if($levenshtein_distance > $closest_match_distance) {
$closest_match = $potential_alias;
$closest_match_distance = $levenshtein_distance;
}
}
$exception_message = 'No route found with alias: \'' . $alias . '\'.';
if($closest_match !== '') {
$exception_message .= ' Did you mean \'' . $closest_match . '\'?';
}
throw new Exception($exception_message);
}
/**
* Rewinds the current route index.
*/
public function rewind(): void
{
$this->index = 0;
}
/**
* Checks if more routes can be iterated.
*
* @return bool More routes
*/
public function valid(): bool
{
return isset($this->routes[$this->index]);
}
/**
* Gets the URL for a given route alias
*
* @param string $alias the alias to match
* @param array<string,mixed> $params the parameters to pass to the route
*/
public function getUrlByAlias(string $alias, array $params = []): string
{
$potential_aliases = [];
foreach ($this->routes as $route) {
$potential_aliases[] = $route->alias;
if ($route->matchAlias($alias)) {
return $route->hydrateUrl($params);
}
}
// use a levenshtein to find the closest match and make a recommendation
$closest_match = '';
$closest_match_distance = 0;
foreach ($potential_aliases as $potential_alias) {
$levenshtein_distance = levenshtein($alias, $potential_alias);
if ($levenshtein_distance > $closest_match_distance) {
$closest_match = $potential_alias;
$closest_match_distance = $levenshtein_distance;
}
}
$exception_message = 'No route found with alias: \'' . $alias . '\'.';
if ($closest_match !== '') {
$exception_message .= ' Did you mean \'' . $closest_match . '\'?';
}
throw new Exception($exception_message);
}
/**
* Rewinds the current route index.
*/
public function rewind(): void
{
$this->index = 0;
}
/**
* Checks if more routes can be iterated.
*
* @return bool More routes
*/
public function valid(): bool
{
return isset($this->routes[$this->index]);
}
/**
* Gets the current route.

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*
@ -165,7 +166,7 @@ class View
$file .= $ext;
}
$is_windows = \strtoupper(\substr(PHP_OS, 0, 3)) === 'WIN';
$is_windows = \strtoupper(\substr(PHP_OS, 0, 3)) === 'WIN';
if (('/' == \substr($file, 0, 1)) || ($is_windows === true && ':' == \substr($file, 1, 1))) {
return $file;
@ -183,7 +184,7 @@ class View
*/
public function e(string $str): string
{
$value = \htmlentities($str);
$value = \htmlentities($str);
echo $value;
return $value;
}

@ -1,6 +1,7 @@
<?php
declare(strict_types=1);
/**
* Flight: An extensible micro-framework.
*

@ -1,3 +1,5 @@
<?php
class ReturnTypeWillChange {}
class ReturnTypeWillChange
{
}

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="pcsg-generated-ruleset">
<description>Created with the PHP Coding Standard Generator. http://edorian.github.io/php-coding-standard-generator/</description>
<arg name="colors"/>
<arg name="tab-width" value="4"/>
<rule ref="PSR12"/>
<!-- <rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/> -->
<file>flight/</file>
<file>tests/</file>
</ruleset>

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*
@ -7,92 +8,97 @@
*/
class CollectionTest extends PHPUnit\Framework\TestCase
{
/**
* @var \flight\util\Collection
*/
private $collection;
/**
* @var \flight\util\Collection
*/
private $collection;
protected function setUp(): void
{
$this->collection = new \flight\util\Collection(['a' => 1, 'b' => 2]);
}
protected function setUp(): void
{
$this->collection = new \flight\util\Collection(['a' => 1, 'b' => 2]);
}
// Get an item
public function testGet()
{
$this->assertEquals(1, $this->collection->a);
}
// Get an item
public function testGet()
{
$this->assertEquals(1, $this->collection->a);
}
// Set an item
public function testSet()
{
$this->collection->c = 3;
$this->assertEquals(3, $this->collection->c);
}
// Set an item
public function testSet()
{
$this->collection->c = 3;
$this->assertEquals(3, $this->collection->c);
}
// Check if an item exists
public function testExists()
{
$this->assertTrue(isset($this->collection->a));
}
// Check if an item exists
public function testExists()
{
$this->assertTrue(isset($this->collection->a));
}
// Unset an item
public function testUnset()
{
unset($this->collection->a);
$this->assertFalse(isset($this->collection->a));
}
// Unset an item
public function testUnset()
{
unset($this->collection->a);
$this->assertFalse(isset($this->collection->a));
}
// Count items
public function testCount()
{
$this->assertEquals(2, count($this->collection));
}
// Count items
public function testCount()
{
$this->assertEquals(2, count($this->collection));
}
// Iterate through items
public function testIterate()
{
$items = [];
foreach ($this->collection as $key => $value) {
$items[$key] = $value;
}
// Iterate through items
public function testIterate()
{
$items = [];
foreach ($this->collection as $key => $value) {
$items[$key] = $value;
}
$this->assertEquals(['a' => 1, 'b' => 2], $items);
}
$this->assertEquals(['a' => 1, 'b' => 2], $items);
}
public function testJsonSerialize()
{
$this->assertEquals(['a' => 1, 'b' => 2], $this->collection->jsonSerialize());
}
public function testJsonSerialize()
{
$this->assertEquals(['a' => 1, 'b' => 2], $this->collection->jsonSerialize());
}
public function testOffsetSetWithNullOffset() {
$this->collection->offsetSet(null, 3);
$this->assertEquals(3, $this->collection->offsetGet(0));
}
public function testOffsetSetWithNullOffset()
{
$this->collection->offsetSet(null, 3);
$this->assertEquals(3, $this->collection->offsetGet(0));
}
public function testOffsetExists() {
$this->collection->a = 1;
$this->assertTrue($this->collection->offsetExists('a'));
}
public function testOffsetExists()
{
$this->collection->a = 1;
$this->assertTrue($this->collection->offsetExists('a'));
}
public function testOffsetUnset() {
$this->collection->a = 1;
$this->assertTrue($this->collection->offsetExists('a'));
$this->collection->offsetUnset('a');
$this->assertFalse($this->collection->offsetExists('a'));
}
public function testOffsetUnset()
{
$this->collection->a = 1;
$this->assertTrue($this->collection->offsetExists('a'));
$this->collection->offsetUnset('a');
$this->assertFalse($this->collection->offsetExists('a'));
}
public function testKeys() {
$this->collection->a = 1;
$this->collection->b = 2;
$this->assertEquals(['a', 'b'], $this->collection->keys());
}
public function testKeys()
{
$this->collection->a = 1;
$this->collection->b = 2;
$this->assertEquals(['a', 'b'], $this->collection->keys());
}
public function testClear() {
$this->collection->a = 1;
$this->collection->b = 2;
$this->assertEquals(['a', 'b'], $this->collection->keys());
$this->collection->clear();
$this->assertEquals(0, $this->collection->count());
}
public function testClear()
{
$this->collection->a = 1;
$this->collection->b = 2;
$this->assertEquals(['a', 'b'], $this->collection->keys());
$this->collection->clear();
$this->assertEquals(0, $this->collection->count());
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*
@ -50,54 +51,56 @@ class DispatcherTest extends PHPUnit\Framework\TestCase
return 'hello';
});
$result = $this->dispatcher->has('map-event');
$result = $this->dispatcher->has('map-event');
$this->assertTrue($result);
$this->assertTrue($result);
}
public function testClearAllRegisteredEvents() {
$this->dispatcher->set('map-event', function () {
return 'hello';
});
public function testClearAllRegisteredEvents()
{
$this->dispatcher->set('map-event', function () {
return 'hello';
});
$this->dispatcher->set('map-event-2', function () {
return 'there';
});
$this->dispatcher->set('map-event-2', function () {
return 'there';
});
$this->dispatcher->clear();
$this->dispatcher->clear();
$result = $this->dispatcher->has('map-event');
$this->assertFalse($result);
$result = $this->dispatcher->has('map-event-2');
$this->assertFalse($result);
}
$result = $this->dispatcher->has('map-event');
$this->assertFalse($result);
$result = $this->dispatcher->has('map-event-2');
$this->assertFalse($result);
}
public function testClearDeclaredRegisteredEvent() {
$this->dispatcher->set('map-event', function () {
return 'hello';
});
public function testClearDeclaredRegisteredEvent()
{
$this->dispatcher->set('map-event', function () {
return 'hello';
});
$this->dispatcher->set('map-event-2', function () {
return 'there';
});
$this->dispatcher->set('map-event-2', function () {
return 'there';
});
$this->dispatcher->clear('map-event');
$this->dispatcher->clear('map-event');
$result = $this->dispatcher->has('map-event');
$this->assertFalse($result);
$result = $this->dispatcher->has('map-event-2');
$this->assertTrue($result);
}
$result = $this->dispatcher->has('map-event');
$this->assertFalse($result);
$result = $this->dispatcher->has('map-event-2');
$this->assertTrue($result);
}
// Map a static function
public function testStaticFunctionMapping()
{
$this->dispatcher->set('map2', 'Hello::sayHi');
// Map a static function
public function testStaticFunctionMapping()
{
$this->dispatcher->set('map2', 'Hello::sayHi');
$result = $this->dispatcher->run('map2');
$result = $this->dispatcher->run('map2');
self::assertEquals('hello', $result);
}
self::assertEquals('hello', $result);
}
// Map a class method
public function testClassMethodMapping()
@ -151,30 +154,33 @@ class DispatcherTest extends PHPUnit\Framework\TestCase
$this->dispatcher->execute(['NonExistentClass', 'nonExistentMethod']);
}
public function testCallFunction4Params() {
$closure = function($param1, $params2, $params3, $param4) {
return 'hello'.$param1.$params2.$params3.$param4;
};
$params = ['param1', 'param2', 'param3', 'param4'];
$result = $this->dispatcher->callFunction($closure, $params);
$this->assertEquals('helloparam1param2param3param4', $result);
}
public function testCallFunction5Params() {
$closure = function($param1, $params2, $params3, $param4, $param5) {
return 'hello'.$param1.$params2.$params3.$param4.$param5;
};
$params = ['param1', 'param2', 'param3', 'param4', 'param5'];
$result = $this->dispatcher->callFunction($closure, $params);
$this->assertEquals('helloparam1param2param3param4param5', $result);
}
public function testCallFunction6Params() {
$closure = function($param1, $params2, $params3, $param4, $param5, $param6) {
return 'hello'.$param1.$params2.$params3.$param4.$param5.$param6;
};
$params = ['param1', 'param2', 'param3', 'param4', 'param5', 'param6'];
$result = $this->dispatcher->callFunction($closure, $params);
$this->assertEquals('helloparam1param2param3param4param5param6', $result);
}
public function testCallFunction4Params()
{
$closure = function ($param1, $params2, $params3, $param4) {
return 'hello' . $param1 . $params2 . $params3 . $param4;
};
$params = ['param1', 'param2', 'param3', 'param4'];
$result = $this->dispatcher->callFunction($closure, $params);
$this->assertEquals('helloparam1param2param3param4', $result);
}
public function testCallFunction5Params()
{
$closure = function ($param1, $params2, $params3, $param4, $param5) {
return 'hello' . $param1 . $params2 . $params3 . $param4 . $param5;
};
$params = ['param1', 'param2', 'param3', 'param4', 'param5'];
$result = $this->dispatcher->callFunction($closure, $params);
$this->assertEquals('helloparam1param2param3param4param5', $result);
}
public function testCallFunction6Params()
{
$closure = function ($param1, $params2, $params3, $param4, $param5, $param6) {
return 'hello' . $param1 . $params2 . $params3 . $param4 . $param5 . $param6;
};
$params = ['param1', 'param2', 'param3', 'param4', 'param5', 'param6'];
$result = $this->dispatcher->callFunction($closure, $params);
$this->assertEquals('helloparam1param2param3param4param5param6', $result);
}
}

@ -13,423 +13,524 @@ use flight\net\Response;
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('<h1>500 Internal Server Error</h1><h3>thrown exception message (20)</h3>');
$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('<h1>404 Not Found</h1><h3>The page you have requested could not be found.</h3> ');
$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 Response {
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): self
{
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;
}
};
});
$this->expectOutputString('skip---exit');
$engine->halt(500, 'skip---exit');
$this->assertEquals(500, $engine->response()->status());
}
public function testRedirect() {
$engine = new Engine();
$engine->redirect('https://github.com', 302);
$this->assertEquals('https://github.com', $engine->response()->headers()['Location']);
$this->assertEquals(302, $engine->response()->status());
}
public function testRedirectWithBaseUrl() {
$engine = new Engine();
$engine->set('flight.base_url', '/subdirectory');
$engine->redirect('/someRoute', 301);
$this->assertEquals('/subdirectory/someRoute', $engine->response()->headers()['Location']);
$this->assertEquals(301, $engine->response()->status());
}
public function testJson() {
$engine = new Engine();
$engine->json(['key1' => 'value1', 'key2' => 'value2']);
$this->expectOutputString('{"key1":"value1","key2":"value2"}');
$this->assertEquals('application/json; charset=utf-8', $engine->response()->headers()['Content-Type']);
$this->assertEquals(200, $engine->response()->status());
}
public function testJsonP() {
$engine = new Engine();
$engine->request()->query['jsonp'] = 'whatever';
$engine->jsonp(['key1' => 'value1', 'key2' => 'value2']);
$this->expectOutputString('whatever({"key1":"value1","key2":"value2"});');
$this->assertEquals('application/javascript; charset=utf-8', $engine->response()->headers()['Content-Type']);
$this->assertEquals(200, $engine->response()->status());
}
public function testJsonPBadParam() {
$engine = new Engine();
$engine->jsonp(['key1' => 'value1', 'key2' => 'value2']);
$this->expectOutputString('({"key1":"value1","key2":"value2"});');
$this->assertEquals('application/javascript; charset=utf-8', $engine->response()->headers()['Content-Type']);
$this->assertEquals(200, $engine->response()->status());
}
public function testEtagSimple() {
$engine = new Engine();
$engine->etag('etag');
$this->assertEquals('"etag"', $engine->response()->headers()['ETag']);
}
public function testEtagWithHttpIfNoneMatch() {
// just need this not to exit...
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$_SERVER['HTTP_IF_NONE_MATCH'] = 'etag';
$engine->etag('etag');
$this->assertEquals('"etag"', $engine->response()->headers()['ETag']);
$this->assertEquals(304, $engine->response()->status());
}
public function testLastModifiedSimple() {
$engine = new Engine();
$engine->lastModified(1234567890);
$this->assertEquals('Fri, 13 Feb 2009 23:31:30 GMT', $engine->response()->headers()['Last-Modified']);
}
public function testLastModifiedWithHttpIfModifiedSince() {
// just need this not to exit...
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = 'Fri, 13 Feb 2009 23:31:30 GMT';
$engine->lastModified(1234567890);
$this->assertEquals('Fri, 13 Feb 2009 23:31:30 GMT', $engine->response()->headers()['Last-Modified']);
$this->assertEquals(304, $engine->response()->status());
}
public function testGetUrl() {
$engine = new Engine;
$engine->route('/path1/@param:[0-9]{3}', function() { echo 'I win'; }, false, 'path1');
$url = $engine->getUrl('path1', [ 'param' => 123 ]);
$this->assertEquals('/path1/123', $url);
}
public function testMiddlewareCallableFunction() {
$engine = new Engine();
$engine->route('/path1/@id', function($id) { echo 'OK'.$id; })
->addMiddleware(function($params) { echo 'before'.$params['id']; });
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before123OK123');
}
public function testMiddlewareCallableFunctionReturnFalse() {
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$engine->route('/path1/@id', function($id) { echo 'OK'.$id; })
->addMiddleware(function($params) { echo 'before'.$params['id']; return false; });
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('Forbiddenbefore123');
$this->assertEquals(403, $engine->response()->status());
}
public function testMiddlewareClassBefore() {
$middleware = new class {
public function before($params) {
echo 'before'.$params['id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id', function($id) { echo 'OK'.$id; })
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before123OK123');
}
public function testMiddlewareClassBeforeAndAfter() {
$middleware = new class {
public function before($params) {
echo 'before'.$params['id'];
}
public function after($params) {
echo 'after'.$params['id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id', function($id) { echo 'OK'.$id; })
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before123OK123after123');
}
public function testMiddlewareClassAfter() {
$middleware = new class {
public function after($params) {
echo 'after'.$params['id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id', function($id) { echo 'OK'.$id; })
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('OK123after123');
}
public function testMiddlewareClassAfterFailedCheck() {
$middleware = new class {
public function after($params) {
echo 'after'.$params['id'];
return false;
}
};
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$engine->route('/path1/@id', function($id) { echo 'OK'.$id; })
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->assertEquals(403, $engine->response()->status());
$this->expectOutputString('ForbiddenOK123after123');
}
public function testMiddlewareCallableFunctionMultiple() {
$engine = new Engine();
$engine->route('/path1/@id', function($id) { echo 'OK'.$id; })
->addMiddleware(function($params) { echo 'before1'.$params['id']; })
->addMiddleware(function($params) { echo 'before2'.$params['id']; });
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before1123before2123OK123');
}
// Pay attention to the order on how the middleware is executed in this test.
public function testMiddlewareClassCallableRouteMultiple() {
$middleware = new class {
public function before($params) {
echo 'before'.$params['another_id'];
}
public function after($params) {
echo 'after'.$params['id'];
}
};
$middleware2 = new class {
public function before($params) {
echo 'before'.$params['id'];
}
public function after($params) {
echo 'after'.$params['id'].$params['another_id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id/subpath1/@another_id', function() { echo 'OK'; })->addMiddleware([ $middleware, $middleware2 ]);
$engine->request()->url = '/path1/123/subpath1/456';
$engine->start();
$this->expectOutputString('before456before123OKafter123456after123');
}
public function testMiddlewareClassGroupRouteMultipleBooyah() {
$middleware = new class {
public function before($params) {
echo 'before'.$params['another_id'];
}
public function after($params) {
echo 'after'.$params['id'];
}
};
$middleware2 = new class {
public function before($params) {
echo 'before'.$params['id'];
}
public function after($params) {
echo 'after'.$params['id'].$params['another_id'];
}
};
$engine = new Engine();
$engine->group('/path1/@id', function($router) {
$router->map('/subpath1/@another_id', function() { echo 'OK'; });
$router->map('/@cool_id', function() { echo 'OK'; });
}, [ $middleware, $middleware2 ]);
$engine->request()->url = '/path1/123/subpath1/456';
$engine->start();
$this->expectOutputString('before456before123OKafter123456after123');
}
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('<h1>500 Internal Server Error</h1><h3>thrown exception message (20)</h3>');
$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('<h1>404 Not Found</h1><h3>The page you have requested could not be found.</h3> ');
$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 Response {
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): self
{
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;
}
};
});
$this->expectOutputString('skip---exit');
$engine->halt(500, 'skip---exit');
$this->assertEquals(500, $engine->response()->status());
}
public function testRedirect()
{
$engine = new Engine();
$engine->redirect('https://github.com', 302);
$this->assertEquals('https://github.com', $engine->response()->headers()['Location']);
$this->assertEquals(302, $engine->response()->status());
}
public function testRedirectWithBaseUrl()
{
$engine = new Engine();
$engine->set('flight.base_url', '/subdirectory');
$engine->redirect('/someRoute', 301);
$this->assertEquals('/subdirectory/someRoute', $engine->response()->headers()['Location']);
$this->assertEquals(301, $engine->response()->status());
}
public function testJson()
{
$engine = new Engine();
$engine->json(['key1' => 'value1', 'key2' => 'value2']);
$this->expectOutputString('{"key1":"value1","key2":"value2"}');
$this->assertEquals('application/json; charset=utf-8', $engine->response()->headers()['Content-Type']);
$this->assertEquals(200, $engine->response()->status());
}
public function testJsonP()
{
$engine = new Engine();
$engine->request()->query['jsonp'] = 'whatever';
$engine->jsonp(['key1' => 'value1', 'key2' => 'value2']);
$this->expectOutputString('whatever({"key1":"value1","key2":"value2"});');
$this->assertEquals('application/javascript; charset=utf-8', $engine->response()->headers()['Content-Type']);
$this->assertEquals(200, $engine->response()->status());
}
public function testJsonPBadParam()
{
$engine = new Engine();
$engine->jsonp(['key1' => 'value1', 'key2' => 'value2']);
$this->expectOutputString('({"key1":"value1","key2":"value2"});');
$this->assertEquals('application/javascript; charset=utf-8', $engine->response()->headers()['Content-Type']);
$this->assertEquals(200, $engine->response()->status());
}
public function testEtagSimple()
{
$engine = new Engine();
$engine->etag('etag');
$this->assertEquals('"etag"', $engine->response()->headers()['ETag']);
}
public function testEtagWithHttpIfNoneMatch()
{
// just need this not to exit...
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$_SERVER['HTTP_IF_NONE_MATCH'] = 'etag';
$engine->etag('etag');
$this->assertEquals('"etag"', $engine->response()->headers()['ETag']);
$this->assertEquals(304, $engine->response()->status());
}
public function testLastModifiedSimple()
{
$engine = new Engine();
$engine->lastModified(1234567890);
$this->assertEquals('Fri, 13 Feb 2009 23:31:30 GMT', $engine->response()->headers()['Last-Modified']);
}
public function testLastModifiedWithHttpIfModifiedSince()
{
// just need this not to exit...
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = 'Fri, 13 Feb 2009 23:31:30 GMT';
$engine->lastModified(1234567890);
$this->assertEquals('Fri, 13 Feb 2009 23:31:30 GMT', $engine->response()->headers()['Last-Modified']);
$this->assertEquals(304, $engine->response()->status());
}
public function testGetUrl()
{
$engine = new Engine();
$engine->route('/path1/@param:[0-9]{3}', function () {
echo 'I win';
}, false, 'path1');
$url = $engine->getUrl('path1', [ 'param' => 123 ]);
$this->assertEquals('/path1/123', $url);
}
public function testMiddlewareCallableFunction()
{
$engine = new Engine();
$engine->route('/path1/@id', function ($id) {
echo 'OK' . $id;
})
->addMiddleware(function ($params) {
echo 'before' . $params['id'];
});
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before123OK123');
}
public function testMiddlewareCallableFunctionReturnFalse()
{
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$engine->route('/path1/@id', function ($id) {
echo 'OK' . $id;
})
->addMiddleware(function ($params) {
echo 'before' . $params['id'];
return false;
});
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('Forbiddenbefore123');
$this->assertEquals(403, $engine->response()->status());
}
public function testMiddlewareClassBefore()
{
$middleware = new class {
public function before($params)
{
echo 'before' . $params['id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id', function ($id) {
echo 'OK' . $id;
})
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before123OK123');
}
public function testMiddlewareClassBeforeAndAfter()
{
$middleware = new class {
public function before($params)
{
echo 'before' . $params['id'];
}
public function after($params)
{
echo 'after' . $params['id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id', function ($id) {
echo 'OK' . $id;
})
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before123OK123after123');
}
public function testMiddlewareClassAfter()
{
$middleware = new class {
public function after($params)
{
echo 'after' . $params['id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id', function ($id) {
echo 'OK' . $id;
})
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('OK123after123');
}
public function testMiddlewareClassAfterFailedCheck()
{
$middleware = new class {
public function after($params)
{
echo 'after' . $params['id'];
return false;
}
};
$engine = new class extends Engine {
public function _halt(int $code = 200, string $message = ''): void
{
$this->response()->status($code);
$this->response()->write($message);
}
};
$engine->route('/path1/@id', function ($id) {
echo 'OK' . $id;
})
->addMiddleware($middleware);
$engine->request()->url = '/path1/123';
$engine->start();
$this->assertEquals(403, $engine->response()->status());
$this->expectOutputString('ForbiddenOK123after123');
}
public function testMiddlewareCallableFunctionMultiple()
{
$engine = new Engine();
$engine->route('/path1/@id', function ($id) {
echo 'OK' . $id;
})
->addMiddleware(function ($params) {
echo 'before1' . $params['id'];
})
->addMiddleware(function ($params) {
echo 'before2' . $params['id'];
});
$engine->request()->url = '/path1/123';
$engine->start();
$this->expectOutputString('before1123before2123OK123');
}
// Pay attention to the order on how the middleware is executed in this test.
public function testMiddlewareClassCallableRouteMultiple()
{
$middleware = new class {
public function before($params)
{
echo 'before' . $params['another_id'];
}
public function after($params)
{
echo 'after' . $params['id'];
}
};
$middleware2 = new class {
public function before($params)
{
echo 'before' . $params['id'];
}
public function after($params)
{
echo 'after' . $params['id'] . $params['another_id'];
}
};
$engine = new Engine();
$engine->route('/path1/@id/subpath1/@another_id', function () {
echo 'OK';
})->addMiddleware([ $middleware, $middleware2 ]);
$engine->request()->url = '/path1/123/subpath1/456';
$engine->start();
$this->expectOutputString('before456before123OKafter123456after123');
}
public function testMiddlewareClassGroupRouteMultipleBooyah()
{
$middleware = new class {
public function before($params)
{
echo 'before' . $params['another_id'];
}
public function after($params)
{
echo 'after' . $params['id'];
}
};
$middleware2 = new class {
public function before($params)
{
echo 'before' . $params['id'];
}
public function after($params)
{
echo 'after' . $params['id'] . $params['another_id'];
}
};
$engine = new Engine();
$engine->group('/path1/@id', function ($router) {
$router->map('/subpath1/@another_id', function () {
echo 'OK';
});
$router->map('/@cool_id', function () {
echo 'OK';
});
}, [ $middleware, $middleware2 ]);
$engine->request()->url = '/path1/123/subpath1/456';
$engine->start();
$this->expectOutputString('before456before123OKafter123456after123');
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*

@ -16,17 +16,18 @@ class FlightTest extends PHPUnit\Framework\TestCase
{
protected function setUp(): void
{
$_SERVER = [];
$_REQUEST = [];
$_SERVER = [];
$_REQUEST = [];
Flight::init();
Flight::setEngine(new Engine());
Flight::setEngine(new Engine());
}
protected function tearDown(): void {
unset($_REQUEST);
unset($_SERVER);
Flight::clear();
}
protected function tearDown(): void
{
unset($_REQUEST);
unset($_SERVER);
Flight::clear();
}
// Checks that default components are loaded
public function testDefaultComponents()
@ -100,124 +101,138 @@ class FlightTest extends PHPUnit\Framework\TestCase
Flight::doesNotExist();
}
public function testStaticRoute() {
Flight::route('/test', function() {
echo 'test';
});
Flight::request()->url = '/test';
$this->expectOutputString('test');
Flight::start();
}
public function testStaticRouteGroup() {
Flight::group('/group', function() {
Flight::route('/test', function() {
echo 'test';
});
});
Flight::request()->url = '/group/test';
$this->expectOutputString('test');
Flight::start();
}
public function testStaticRouteGet() {
// can't actually get "get" because that gets a variable
Flight::route('GET /test', function() {
echo 'test get';
});
$_SERVER['REQUEST_METHOD'] = 'GET';
Flight::request()->url = '/test';
$this->expectOutputString('test get');
Flight::start();
}
public function testStaticRoutePost() {
Flight::post('/test', function() {
echo 'test post';
});
$_SERVER['REQUEST_METHOD'] = 'POST';
Flight::request()->url = '/test';
$this->expectOutputString('test post');
Flight::start();
}
public function testStaticRoutePut() {
Flight::put('/test', function() {
echo 'test put';
});
$_SERVER['REQUEST_METHOD'] = 'PUT';
Flight::request()->url = '/test';
$this->expectOutputString('test put');
Flight::start();
}
public function testStaticRoutePatch() {
Flight::patch('/test', function() {
echo 'test patch';
});
$_SERVER['REQUEST_METHOD'] = 'PATCH';
Flight::request()->url = '/test';
$this->expectOutputString('test patch');
Flight::start();
}
public function testStaticRouteDelete() {
Flight::delete('/test', function() {
echo 'test delete';
});
$_SERVER['REQUEST_METHOD'] = 'DELETE';
Flight::request()->url = '/test';
$this->expectOutputString('test delete');
Flight::start();
}
public function testGetUrl() {
Flight::route('/path1/@param:[a-zA-Z0-9]{2,3}', function() { echo 'I win'; }, false, 'path1');
$url = Flight::getUrl('path1', [ 'param' => 123 ]);
$this->assertEquals('/path1/123', $url);
}
public function testRouteGetUrlWithGroupSimpleParams() {
Flight::group('/path1/@id', function() {
Flight::route('/@name', function() { echo 'whatever'; }, false, 'path1');
});
$url = Flight::getUrl('path1', ['id' => 123, 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testRouteGetUrlNestedGroups() {
Flight::group('/user', function () {
Flight::group('/all_users', function () {
Flight::group('/check_user', function () {
Flight::group('/check_one', function () {
Flight::route("/normalpath", function () {
echo "normalpath";
},false,"normalpathalias");
});
});
});
});
$url = Flight::getUrl('normalpathalias');
$this->assertEquals('/user/all_users/check_user/check_one/normalpath', $url);
}
public function testStaticRoute()
{
Flight::route('/test', function () {
echo 'test';
});
Flight::request()->url = '/test';
$this->expectOutputString('test');
Flight::start();
}
public function testStaticRouteGroup()
{
Flight::group('/group', function () {
Flight::route('/test', function () {
echo 'test';
});
});
Flight::request()->url = '/group/test';
$this->expectOutputString('test');
Flight::start();
}
public function testStaticRouteGet()
{
// can't actually get "get" because that gets a variable
Flight::route('GET /test', function () {
echo 'test get';
});
$_SERVER['REQUEST_METHOD'] = 'GET';
Flight::request()->url = '/test';
$this->expectOutputString('test get');
Flight::start();
}
public function testStaticRoutePost()
{
Flight::post('/test', function () {
echo 'test post';
});
$_SERVER['REQUEST_METHOD'] = 'POST';
Flight::request()->url = '/test';
$this->expectOutputString('test post');
Flight::start();
}
public function testStaticRoutePut()
{
Flight::put('/test', function () {
echo 'test put';
});
$_SERVER['REQUEST_METHOD'] = 'PUT';
Flight::request()->url = '/test';
$this->expectOutputString('test put');
Flight::start();
}
public function testStaticRoutePatch()
{
Flight::patch('/test', function () {
echo 'test patch';
});
$_SERVER['REQUEST_METHOD'] = 'PATCH';
Flight::request()->url = '/test';
$this->expectOutputString('test patch');
Flight::start();
}
public function testStaticRouteDelete()
{
Flight::delete('/test', function () {
echo 'test delete';
});
$_SERVER['REQUEST_METHOD'] = 'DELETE';
Flight::request()->url = '/test';
$this->expectOutputString('test delete');
Flight::start();
}
public function testGetUrl()
{
Flight::route('/path1/@param:[a-zA-Z0-9]{2,3}', function () {
echo 'I win';
}, false, 'path1');
$url = Flight::getUrl('path1', [ 'param' => 123 ]);
$this->assertEquals('/path1/123', $url);
}
public function testRouteGetUrlWithGroupSimpleParams()
{
Flight::group('/path1/@id', function () {
Flight::route('/@name', function () {
echo 'whatever';
}, false, 'path1');
});
$url = Flight::getUrl('path1', ['id' => 123, 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testRouteGetUrlNestedGroups()
{
Flight::group('/user', function () {
Flight::group('/all_users', function () {
Flight::group('/check_user', function () {
Flight::group('/check_one', function () {
Flight::route("/normalpath", function () {
echo "normalpath";
}, false, "normalpathalias");
});
});
});
});
$url = Flight::getUrl('normalpathalias');
$this->assertEquals('/user/all_users/check_user/check_one/normalpath', $url);
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*
@ -119,35 +120,39 @@ class LoaderTest extends PHPUnit\Framework\TestCase
self::assertInstanceOf(Factory::class, $obj);
}
public function testUnregisterClass() {
$this->loader->register('g', 'User');
$current_class = $this->loader->get('g');
$this->assertEquals([ 'User', [], null ], $current_class);
$this->loader->unregister('g');
$unregistered_class_result = $this->loader->get('g');
$this->assertNull($unregistered_class_result);
}
public function testNewInstance6Params() {
$TesterClass = $this->loader->newInstance('TesterClass', ['Bob','Fred', 'Joe', 'Jane', 'Sally', 'Suzie']);
$this->assertEquals('Bob', $TesterClass->param1);
$this->assertEquals('Fred', $TesterClass->param2);
$this->assertEquals('Joe', $TesterClass->param3);
$this->assertEquals('Jane', $TesterClass->param4);
$this->assertEquals('Sally', $TesterClass->param5);
$this->assertEquals('Suzie', $TesterClass->param6);
}
public function testAddDirectoryAsArray() {
$loader = new class extends Loader {
public function getDirectories() {
return self::$dirs;
}
};
$loader->addDirectory([__DIR__ . '/classes']);
self::assertEquals([
dirname(__DIR__),
__DIR__ . '/classes'
], $loader->getDirectories());
}
public function testUnregisterClass()
{
$this->loader->register('g', 'User');
$current_class = $this->loader->get('g');
$this->assertEquals([ 'User', [], null ], $current_class);
$this->loader->unregister('g');
$unregistered_class_result = $this->loader->get('g');
$this->assertNull($unregistered_class_result);
}
public function testNewInstance6Params()
{
$TesterClass = $this->loader->newInstance('TesterClass', ['Bob','Fred', 'Joe', 'Jane', 'Sally', 'Suzie']);
$this->assertEquals('Bob', $TesterClass->param1);
$this->assertEquals('Fred', $TesterClass->param2);
$this->assertEquals('Joe', $TesterClass->param3);
$this->assertEquals('Jane', $TesterClass->param4);
$this->assertEquals('Sally', $TesterClass->param5);
$this->assertEquals('Suzie', $TesterClass->param6);
}
public function testAddDirectoryAsArray()
{
$loader = new class extends Loader {
public function getDirectories()
{
return self::$dirs;
}
};
$loader->addDirectory([__DIR__ . '/classes']);
self::assertEquals([
dirname(__DIR__),
__DIR__ . '/classes'
], $loader->getDirectories());
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*

@ -21,91 +21,102 @@ class PdoWrapperTest extends PHPUnit\Framework\TestCase
protected function setUp(): void
{
$this->pdo_wrapper = new PdoWrapper('sqlite::memory:');
// create a test table and insert 3 rows of data
$this->pdo_wrapper->exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)');
$this->pdo_wrapper->exec('INSERT INTO test (name) VALUES ("one")');
$this->pdo_wrapper->exec('INSERT INTO test (name) VALUES ("two")');
$this->pdo_wrapper->exec('INSERT INTO test (name) VALUES ("three")');
// create a test table and insert 3 rows of data
$this->pdo_wrapper->exec('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)');
$this->pdo_wrapper->exec('INSERT INTO test (name) VALUES ("one")');
$this->pdo_wrapper->exec('INSERT INTO test (name) VALUES ("two")');
$this->pdo_wrapper->exec('INSERT INTO test (name) VALUES ("three")');
}
protected function tearDown(): void
{
// delete the test table
$this->pdo_wrapper->exec('DROP TABLE test');
}
public function testRunQuerySelectAllStatement() {
$statement = $this->pdo_wrapper->runQuery('SELECT * FROM test');
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertCount(3, $statement->fetchAll());
}
public function testRunQuerySelectOneStatement() {
$statement = $this->pdo_wrapper->runQuery('SELECT * FROM test WHERE id = 1');
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertCount(1, $statement->fetchAll());
}
public function testRunQueryInsertStatement() {
$statement = $this->pdo_wrapper->runQuery('INSERT INTO test (name) VALUES ("four")');
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertEquals(1, $statement->rowCount());
}
public function testRunQueryUpdateStatement() {
$statement = $this->pdo_wrapper->runQuery('UPDATE test SET name = "something" WHERE name LIKE ?', ['%t%']);
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertEquals(2, $statement->rowCount());
}
public function testRunQueryDeleteStatement() {
$statement = $this->pdo_wrapper->runQuery('DELETE FROM test WHERE name LIKE ?', ['%t%']);
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertEquals(2, $statement->rowCount());
}
public function testFetchField() {
$id = $this->pdo_wrapper->fetchField('SELECT id FROM test WHERE name = ?', ['two']);
$this->assertEquals(2, $id);
}
public function testFetchRow() {
$row = $this->pdo_wrapper->fetchRow('SELECT * FROM test WHERE name = ?', ['two']);
$this->assertEquals(2, $row['id']);
$this->assertEquals('two', $row['name']);
}
public function testFetchAll() {
$rows = $this->pdo_wrapper->fetchAll('SELECT * FROM test');
$this->assertCount(3, $rows);
$this->assertEquals(1, $rows[0]['id']);
$this->assertEquals('one', $rows[0]['name']);
$this->assertEquals(2, $rows[1]['id']);
$this->assertEquals('two', $rows[1]['name']);
$this->assertEquals(3, $rows[2]['id']);
$this->assertEquals('three', $rows[2]['name']);
}
public function testFetchAllWithNamedParams() {
$rows = $this->pdo_wrapper->fetchAll('SELECT * FROM test WHERE name = :name', [ 'name' => 'two']);
$this->assertCount(1, $rows);
$this->assertEquals(2, $rows[0]['id']);
$this->assertEquals('two', $rows[0]['name']);
}
public function testFetchAllWithInInt() {
$rows = $this->pdo_wrapper->fetchAll('SELECT id FROM test WHERE id IN(?)', [ [1,2 ]]);
$this->assertEquals(2, count($rows));
}
public function testFetchAllWithInString() {
$rows = $this->pdo_wrapper->fetchAll('SELECT id FROM test WHERE name IN(?)', [ ['one','two' ]]);
$this->assertEquals(2, count($rows));
}
public function testFetchAllWithInStringCommas() {
$rows = $this->pdo_wrapper->fetchAll('SELECT id FROM test WHERE id > ? AND name IN(?)', [ 0, 'one,two' ]);
$this->assertEquals(2, count($rows));
}
protected function tearDown(): void
{
// delete the test table
$this->pdo_wrapper->exec('DROP TABLE test');
}
public function testRunQuerySelectAllStatement()
{
$statement = $this->pdo_wrapper->runQuery('SELECT * FROM test');
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertCount(3, $statement->fetchAll());
}
public function testRunQuerySelectOneStatement()
{
$statement = $this->pdo_wrapper->runQuery('SELECT * FROM test WHERE id = 1');
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertCount(1, $statement->fetchAll());
}
public function testRunQueryInsertStatement()
{
$statement = $this->pdo_wrapper->runQuery('INSERT INTO test (name) VALUES ("four")');
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertEquals(1, $statement->rowCount());
}
public function testRunQueryUpdateStatement()
{
$statement = $this->pdo_wrapper->runQuery('UPDATE test SET name = "something" WHERE name LIKE ?', ['%t%']);
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertEquals(2, $statement->rowCount());
}
public function testRunQueryDeleteStatement()
{
$statement = $this->pdo_wrapper->runQuery('DELETE FROM test WHERE name LIKE ?', ['%t%']);
$this->assertInstanceOf(PDOStatement::class, $statement);
$this->assertEquals(2, $statement->rowCount());
}
public function testFetchField()
{
$id = $this->pdo_wrapper->fetchField('SELECT id FROM test WHERE name = ?', ['two']);
$this->assertEquals(2, $id);
}
public function testFetchRow()
{
$row = $this->pdo_wrapper->fetchRow('SELECT * FROM test WHERE name = ?', ['two']);
$this->assertEquals(2, $row['id']);
$this->assertEquals('two', $row['name']);
}
public function testFetchAll()
{
$rows = $this->pdo_wrapper->fetchAll('SELECT * FROM test');
$this->assertCount(3, $rows);
$this->assertEquals(1, $rows[0]['id']);
$this->assertEquals('one', $rows[0]['name']);
$this->assertEquals(2, $rows[1]['id']);
$this->assertEquals('two', $rows[1]['name']);
$this->assertEquals(3, $rows[2]['id']);
$this->assertEquals('three', $rows[2]['name']);
}
public function testFetchAllWithNamedParams()
{
$rows = $this->pdo_wrapper->fetchAll('SELECT * FROM test WHERE name = :name', [ 'name' => 'two']);
$this->assertCount(1, $rows);
$this->assertEquals(2, $rows[0]['id']);
$this->assertEquals('two', $rows[0]['name']);
}
public function testFetchAllWithInInt()
{
$rows = $this->pdo_wrapper->fetchAll('SELECT id FROM test WHERE id IN(?)', [ [1,2 ]]);
$this->assertEquals(2, count($rows));
}
public function testFetchAllWithInString()
{
$rows = $this->pdo_wrapper->fetchAll('SELECT id FROM test WHERE name IN(?)', [ ['one','two' ]]);
$this->assertEquals(2, count($rows));
}
public function testFetchAllWithInStringCommas()
{
$rows = $this->pdo_wrapper->fetchAll('SELECT id FROM test WHERE id > ? AND name IN(?)', [ 0, 'one,two' ]);
$this->assertEquals(2, count($rows));
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*
@ -15,8 +16,8 @@ class RequestTest extends PHPUnit\Framework\TestCase
protected function setUp(): void
{
$_SERVER = [];
$_REQUEST = [];
$_SERVER = [];
$_REQUEST = [];
$_SERVER['REQUEST_URI'] = '/';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$_SERVER['REQUEST_METHOD'] = 'GET';
@ -34,10 +35,11 @@ class RequestTest extends PHPUnit\Framework\TestCase
$this->request = new Request();
}
protected function tearDown(): void {
unset($_REQUEST);
unset($_SERVER);
}
protected function tearDown(): void
{
unset($_REQUEST);
unset($_SERVER);
}
public function testDefaults()
{
@ -156,41 +158,44 @@ class RequestTest extends PHPUnit\Framework\TestCase
self::assertEquals('http', $request->scheme);
}
public function testInitUrlSameAsBaseDirectory() {
$request = new Request([
'url' => '/vagrant/public/flightphp',
'base' => '/vagrant/public',
'query' => new Collection(),
'type' => ''
]);
$this->assertEquals('/flightphp', $request->url);
}
public function testInitNoUrl() {
$request = new Request([
'url' => '',
'base' => '/vagrant/public',
'type' => ''
]);
$this->assertEquals('/', $request->url);
}
public function testInitWithJsonBody() {
// create dummy file to pull request body from
$tmpfile = tmpfile();
$stream_path = stream_get_meta_data($tmpfile)['uri'];
file_put_contents($stream_path, '{"foo":"bar"}');
$_SERVER['REQUEST_METHOD'] = 'POST';
$request = new Request([
'url' => '/something/fancy',
'base' => '/vagrant/public',
'type' => 'application/json',
'length' => 13,
'data' => new Collection(),
'query' => new Collection(),
'stream_path' => $stream_path
]);
$this->assertEquals([ 'foo' => 'bar' ], $request->data->getData());
$this->assertEquals('{"foo":"bar"}', $request->getBody());
}
public function testInitUrlSameAsBaseDirectory()
{
$request = new Request([
'url' => '/vagrant/public/flightphp',
'base' => '/vagrant/public',
'query' => new Collection(),
'type' => ''
]);
$this->assertEquals('/flightphp', $request->url);
}
public function testInitNoUrl()
{
$request = new Request([
'url' => '',
'base' => '/vagrant/public',
'type' => ''
]);
$this->assertEquals('/', $request->url);
}
public function testInitWithJsonBody()
{
// create dummy file to pull request body from
$tmpfile = tmpfile();
$stream_path = stream_get_meta_data($tmpfile)['uri'];
file_put_contents($stream_path, '{"foo":"bar"}');
$_SERVER['REQUEST_METHOD'] = 'POST';
$request = new Request([
'url' => '/something/fancy',
'base' => '/vagrant/public',
'type' => 'application/json',
'length' => 13,
'data' => new Collection(),
'query' => new Collection(),
'stream_path' => $stream_path
]);
$this->assertEquals([ 'foo' => 'bar' ], $request->data->getData());
$this->assertEquals('{"foo":"bar"}', $request->getBody());
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*
@ -12,216 +13,236 @@ use flight\util\Collection;
class ResponseTest extends PHPUnit\Framework\TestCase
{
protected function setUp(): void
{
$_SERVER = [];
$_REQUEST = [];
$_SERVER = [];
$_REQUEST = [];
$_GET = [];
$_POST = [];
$_COOKIE = [];
$_FILES = [];
}
protected function tearDown(): void {
unset($_REQUEST);
unset($_SERVER);
}
public function testStatusDefault() {
$response = new Response();
$this->assertSame(200, $response->status());
}
public function testStatusValidCode() {
$response = new Response();
$response->status(200);
$this->assertEquals(200, $response->status());
}
public function testStatusInvalidCode() {
$response = new Response();
$this->expectException(Exception::class);
$this->expectExceptionMessage('Invalid status code.');
$response->status(999);
}
public function testStatusReturnObject() {
$response = new Response();
$this->assertEquals($response, $response->status(200));
}
public function testHeaderSingle() {
$response = new Response();
$response->header('Content-Type', 'text/html');
$this->assertEquals(['Content-Type' => 'text/html'], $response->headers());
}
public function testHeaderSingleKeepCaseSensitive() {
$response = new Response();
$response->header('content-type', 'text/html');
$response->header('x-test', 'test');
$this->assertEquals(['content-type' => 'text/html', 'x-test' => 'test'], $response->headers());
}
public function testHeaderArray() {
$response = new Response();
$response->header(['Content-Type' => 'text/html', 'X-Test' => 'test']);
$this->assertEquals(['Content-Type' => 'text/html', 'X-Test' => 'test'], $response->headers());
}
public function testHeaderReturnObject() {
$response = new Response();
$this->assertEquals($response, $response->header('Content-Type', 'text/html'));
}
public function testWrite() {
$response = new class extends Response {
public function getBody() {
return $this->body;
}
};
$response->write('test');
$this->assertEquals('test', $response->getBody());
}
public function testWriteEmptyString() {
$response = new class extends Response {
public function getBody() {
return $this->body;
}
};
$response->write('');
$this->assertEquals('', $response->getBody());
}
public function testWriteReturnObject() {
$response = new Response();
$this->assertEquals($response, $response->write('test'));
}
public function testClear() {
$response = new class extends Response {
public function getBody() {
return $this->body;
}
};
$response->write('test');
$response->status(404);
$response->header('Content-Type', 'text/html');
$response->clear();
$this->assertEquals('', $response->getBody());
$this->assertEquals(200, $response->status());
$this->assertEquals([], $response->headers());
}
public function testCacheSimple() {
$response = new Response();
$cache_time = time() + 60;
$response->cache($cache_time);
$this->assertEquals([
'Expires' => gmdate('D, d M Y H:i:s', $cache_time) . ' GMT',
'Cache-Control' => 'max-age=60'
], $response->headers());
}
public function testCacheSimpleWithString() {
$response = new Response();
$cache_time = time() + 60;
$response->cache('now +60 seconds');
$this->assertEquals([
'Expires' => gmdate('D, d M Y H:i:s', $cache_time) . ' GMT',
'Cache-Control' => 'max-age=60'
], $response->headers());
}
public function testCacheSimpleWithPragma() {
$response = new Response();
$cache_time = time() + 60;
$response->header('Pragma', 'no-cache');
$response->cache($cache_time);
$this->assertEquals([
'Expires' => gmdate('D, d M Y H:i:s', $cache_time) . ' GMT',
'Cache-Control' => 'max-age=60'
], $response->headers());
}
public function testCacheFalseExpiresValue() {
$response = new Response();
$response->cache(false);
$this->assertEquals([
'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
'Cache-Control' => [
protected function tearDown(): void
{
unset($_REQUEST);
unset($_SERVER);
}
public function testStatusDefault()
{
$response = new Response();
$this->assertSame(200, $response->status());
}
public function testStatusValidCode()
{
$response = new Response();
$response->status(200);
$this->assertEquals(200, $response->status());
}
public function testStatusInvalidCode()
{
$response = new Response();
$this->expectException(Exception::class);
$this->expectExceptionMessage('Invalid status code.');
$response->status(999);
}
public function testStatusReturnObject()
{
$response = new Response();
$this->assertEquals($response, $response->status(200));
}
public function testHeaderSingle()
{
$response = new Response();
$response->header('Content-Type', 'text/html');
$this->assertEquals(['Content-Type' => 'text/html'], $response->headers());
}
public function testHeaderSingleKeepCaseSensitive()
{
$response = new Response();
$response->header('content-type', 'text/html');
$response->header('x-test', 'test');
$this->assertEquals(['content-type' => 'text/html', 'x-test' => 'test'], $response->headers());
}
public function testHeaderArray()
{
$response = new Response();
$response->header(['Content-Type' => 'text/html', 'X-Test' => 'test']);
$this->assertEquals(['Content-Type' => 'text/html', 'X-Test' => 'test'], $response->headers());
}
public function testHeaderReturnObject()
{
$response = new Response();
$this->assertEquals($response, $response->header('Content-Type', 'text/html'));
}
public function testWrite()
{
$response = new class extends Response {
public function getBody()
{
return $this->body;
}
};
$response->write('test');
$this->assertEquals('test', $response->getBody());
}
public function testWriteEmptyString()
{
$response = new class extends Response {
public function getBody()
{
return $this->body;
}
};
$response->write('');
$this->assertEquals('', $response->getBody());
}
public function testWriteReturnObject()
{
$response = new Response();
$this->assertEquals($response, $response->write('test'));
}
public function testClear()
{
$response = new class extends Response {
public function getBody()
{
return $this->body;
}
};
$response->write('test');
$response->status(404);
$response->header('Content-Type', 'text/html');
$response->clear();
$this->assertEquals('', $response->getBody());
$this->assertEquals(200, $response->status());
$this->assertEquals([], $response->headers());
}
public function testCacheSimple()
{
$response = new Response();
$cache_time = time() + 60;
$response->cache($cache_time);
$this->assertEquals([
'Expires' => gmdate('D, d M Y H:i:s', $cache_time) . ' GMT',
'Cache-Control' => 'max-age=60'
], $response->headers());
}
public function testCacheSimpleWithString()
{
$response = new Response();
$cache_time = time() + 60;
$response->cache('now +60 seconds');
$this->assertEquals([
'Expires' => gmdate('D, d M Y H:i:s', $cache_time) . ' GMT',
'Cache-Control' => 'max-age=60'
], $response->headers());
}
public function testCacheSimpleWithPragma()
{
$response = new Response();
$cache_time = time() + 60;
$response->header('Pragma', 'no-cache');
$response->cache($cache_time);
$this->assertEquals([
'Expires' => gmdate('D, d M Y H:i:s', $cache_time) . ' GMT',
'Cache-Control' => 'max-age=60'
], $response->headers());
}
public function testCacheFalseExpiresValue()
{
$response = new Response();
$response->cache(false);
$this->assertEquals([
'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
'Cache-Control' => [
'no-store, no-cache, must-revalidate',
'post-check=0, pre-check=0',
'max-age=0',
],
'Pragma' => 'no-cache'
], $response->headers());
}
public function testSendHeadersRegular() {
$response = new class extends Response {
protected $test_sent_headers = [];
protected array $headers = [
'Cache-Control' => [
'no-store, no-cache, must-revalidate',
'post-check=0, pre-check=0',
'max-age=0',
]
];
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response
{
$this->test_sent_headers[] = $header_string;
return $this;
}
public function getSentHeaders(): array
{
return $this->test_sent_headers;
}
};
$response->header('Content-Type', 'text/html');
$response->header('X-Test', 'test');
$response->write('Something');
$response->sendHeaders();
$sent_headers = $response->getSentHeaders();
$this->assertEquals([
'HTTP/1.1 200 OK',
'Cache-Control: no-store, no-cache, must-revalidate',
'Cache-Control: post-check=0, pre-check=0',
'Cache-Control: max-age=0',
'Content-Type: text/html',
'X-Test: test',
'Content-Length: 9'
], $sent_headers);
}
public function testSentDefault() {
$response = new Response();
$this->assertFalse($response->sent());
}
public function testSentTrue() {
$response = new class extends Response {
protected $test_sent_headers = [];
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response
{
$this->test_sent_headers[] = $header_string;
return $this;
}
};
$response->header('Content-Type', 'text/html');
$response->header('X-Test', 'test');
$response->write('Something');
$this->expectOutputString('Something');
$response->send();
$this->assertTrue($response->sent());
}
'Pragma' => 'no-cache'
], $response->headers());
}
public function testSendHeadersRegular()
{
$response = new class extends Response {
protected $test_sent_headers = [];
protected array $headers = [
'Cache-Control' => [
'no-store, no-cache, must-revalidate',
'post-check=0, pre-check=0',
'max-age=0',
]
];
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response
{
$this->test_sent_headers[] = $header_string;
return $this;
}
public function getSentHeaders(): array
{
return $this->test_sent_headers;
}
};
$response->header('Content-Type', 'text/html');
$response->header('X-Test', 'test');
$response->write('Something');
$response->sendHeaders();
$sent_headers = $response->getSentHeaders();
$this->assertEquals([
'HTTP/1.1 200 OK',
'Cache-Control: no-store, no-cache, must-revalidate',
'Cache-Control: post-check=0, pre-check=0',
'Cache-Control: max-age=0',
'Content-Type: text/html',
'X-Test: test',
'Content-Length: 9'
], $sent_headers);
}
public function testSentDefault()
{
$response = new Response();
$this->assertFalse($response->sent());
}
public function testSentTrue()
{
$response = new class extends Response {
protected $test_sent_headers = [];
public function setRealHeader(string $header_string, bool $replace = true, int $response_code = 0): Response
{
$this->test_sent_headers[] = $header_string;
return $this;
}
};
$response->header('Content-Type', 'text/html');
$response->header('X-Test', 'test');
$response->write('Something');
$this->expectOutputString('Something');
$response->send();
$this->assertTrue($response->sent());
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*
@ -20,17 +21,18 @@ class RouterTest extends PHPUnit\Framework\TestCase
protected function setUp(): void
{
$_SERVER = [];
$_REQUEST = [];
$_SERVER = [];
$_REQUEST = [];
$this->router = new Router();
$this->request = new Request();
$this->dispatcher = new Dispatcher();
}
protected function tearDown(): void {
unset($_REQUEST);
unset($_SERVER);
}
protected function tearDown(): void
{
unset($_REQUEST);
unset($_SERVER);
}
// Simple output
public function ok()
@ -105,7 +107,7 @@ class RouterTest extends PHPUnit\Framework\TestCase
$this->check('OK');
}
// Simple path with trailing slash
// Simple path with trailing slash
public function testPathRouteTrailingSlash()
{
$this->router->map('/path/', [$this, 'ok']);
@ -114,7 +116,7 @@ class RouterTest extends PHPUnit\Framework\TestCase
$this->check('OK');
}
public function testGetRouteShortcut()
public function testGetRouteShortcut()
{
$this->router->get('/path', [$this, 'ok']);
$this->request->url = '/path';
@ -152,29 +154,32 @@ class RouterTest extends PHPUnit\Framework\TestCase
$this->check('OK');
}
public function testPutRouteShortcut() {
$this->router->put('/path', [$this, 'ok']);
$this->request->url = '/path';
$this->request->method = 'PUT';
public function testPutRouteShortcut()
{
$this->router->put('/path', [$this, 'ok']);
$this->request->url = '/path';
$this->request->method = 'PUT';
$this->check('OK');
}
$this->check('OK');
}
public function testPatchRouteShortcut() {
$this->router->patch('/path', [$this, 'ok']);
$this->request->url = '/path';
$this->request->method = 'PATCH';
public function testPatchRouteShortcut()
{
$this->router->patch('/path', [$this, 'ok']);
$this->request->url = '/path';
$this->request->method = 'PATCH';
$this->check('OK');
}
$this->check('OK');
}
public function testDeleteRouteShortcut() {
$this->router->delete('/path', [$this, 'ok']);
$this->request->url = '/path';
$this->request->method = 'DELETE';
public function testDeleteRouteShortcut()
{
$this->router->delete('/path', [$this, 'ok']);
$this->request->url = '/path';
$this->request->method = 'DELETE';
$this->check('OK');
}
$this->check('OK');
}
// Test regular expression matching
public function testRegEx()
@ -249,18 +254,19 @@ class RouterTest extends PHPUnit\Framework\TestCase
$this->check('OK');
}
public function testWildcardDuplicate() {
$this->router->map('/account/*' , [$this, 'ok']);
$this->request->url = '/account/account/account';
$this->check('OK');
}
public function testWildcardDuplicate()
{
$this->router->map('/account/*', [$this, 'ok']);
$this->request->url = '/account/account/account';
$this->check('OK');
}
public function testRouteWithLongQueryParamWithMultilineEncoded()
{
$this->router->map('GET /api/intune/hey', [$this, 'ok']);
$this->request->url = '/api/intune/hey?error=access_denied&error_description=AADSTS65004%3a+User+declined+to+consent+to+access+the+app.%0d%0aTrace+ID%3a+747c0cc1-ccbd-4e53-8e2f-48812eb24100%0d%0aCorrelation+ID%3a+362e3cb3-20ef-400b-904e-9983bd989184%0d%0aTimestamp%3a+2022-09-08+09%3a58%3a12Z&error_uri=https%3a%2f%2flogin.microsoftonline.com%2ferror%3fcode%3d65004&admin_consent=True&state=x2EUE0fcSj#';
$this->check('OK');
}
public function testRouteWithLongQueryParamWithMultilineEncoded()
{
$this->router->map('GET /api/intune/hey', [$this, 'ok']);
$this->request->url = '/api/intune/hey?error=access_denied&error_description=AADSTS65004%3a+User+declined+to+consent+to+access+the+app.%0d%0aTrace+ID%3a+747c0cc1-ccbd-4e53-8e2f-48812eb24100%0d%0aCorrelation+ID%3a+362e3cb3-20ef-400b-904e-9983bd989184%0d%0aTimestamp%3a+2022-09-08+09%3a58%3a12Z&error_uri=https%3a%2f%2flogin.microsoftonline.com%2ferror%3fcode%3d65004&admin_consent=True&state=x2EUE0fcSj#';
$this->check('OK');
}
// Check if route object was passed
public function testRouteObjectPassing()
@ -298,17 +304,21 @@ class RouterTest extends PHPUnit\Framework\TestCase
$this->check();
}
public function testRouteBeingReturned() {
$route = $this->router->map('/hi', function() {});
$route_in_router = $this->router->getRoutes()[0];
$this->assertSame($route, $route_in_router);
}
public function testRouteBeingReturned()
{
$route = $this->router->map('/hi', function () {
});
$route_in_router = $this->router->getRoutes()[0];
$this->assertSame($route, $route_in_router);
}
public function testRouteSetAlias() {
$route = $this->router->map('/hi', function() {});
$route->setAlias('hello');
$this->assertEquals('hello', $route->alias);
}
public function testRouteSetAlias()
{
$route = $this->router->map('/hi', function () {
});
$route->setAlias('hello');
$this->assertEquals('hello', $route->alias);
}
// Test splat
public function testSplatWildcard()
@ -374,230 +384,249 @@ class RouterTest extends PHPUnit\Framework\TestCase
$this->check('цветя');
}
public function testGetAndClearRoutes() {
$this->router->map('/path1', [$this, 'ok']);
$this->router->map('/path2', [$this, 'ok']);
$this->router->map('/path3', [$this, 'ok']);
$this->router->map('/path4', [$this, 'ok']);
$this->router->map('/path5', [$this, 'ok']);
$this->router->map('/path6', [$this, 'ok']);
$this->router->map('/path7', [$this, 'ok']);
$this->router->map('/path8', [$this, 'ok']);
$this->router->map('/path9', [$this, 'ok']);
$routes = $this->router->getRoutes();
$this->assertEquals(9, count($routes));
$this->router->clear();
$this->assertEquals(0, count($this->router->getRoutes()));
}
public function testResetRoutes() {
$router = new class extends Router {
public function getIndex() {
return $this->index;
}
};
$router->map('/path1', [$this, 'ok']);
$router->map('/path2', [$this, 'ok']);
$router->map('/path3', [$this, 'ok']);
$router->map('/path4', [$this, 'ok']);
$router->map('/path5', [$this, 'ok']);
$router->map('/path6', [$this, 'ok']);
$router->map('/path7', [$this, 'ok']);
$router->map('/path8', [$this, 'ok']);
$router->map('/path9', [$this, 'ok']);
$router->next();
$router->next();
$router->next();
$this->assertEquals(3, $router->getIndex());
$router->reset();
$this->assertEquals(0, $router->getIndex());
}
// Passing URL parameters
public function testGetAndClearRoutes()
{
$this->router->map('/path1', [$this, 'ok']);
$this->router->map('/path2', [$this, 'ok']);
$this->router->map('/path3', [$this, 'ok']);
$this->router->map('/path4', [$this, 'ok']);
$this->router->map('/path5', [$this, 'ok']);
$this->router->map('/path6', [$this, 'ok']);
$this->router->map('/path7', [$this, 'ok']);
$this->router->map('/path8', [$this, 'ok']);
$this->router->map('/path9', [$this, 'ok']);
$routes = $this->router->getRoutes();
$this->assertEquals(9, count($routes));
$this->router->clear();
$this->assertEquals(0, count($this->router->getRoutes()));
}
public function testResetRoutes()
{
$router = new class extends Router {
public function getIndex()
{
return $this->index;
}
};
$router->map('/path1', [$this, 'ok']);
$router->map('/path2', [$this, 'ok']);
$router->map('/path3', [$this, 'ok']);
$router->map('/path4', [$this, 'ok']);
$router->map('/path5', [$this, 'ok']);
$router->map('/path6', [$this, 'ok']);
$router->map('/path7', [$this, 'ok']);
$router->map('/path8', [$this, 'ok']);
$router->map('/path9', [$this, 'ok']);
$router->next();
$router->next();
$router->next();
$this->assertEquals(3, $router->getIndex());
$router->reset();
$this->assertEquals(0, $router->getIndex());
}
// Passing URL parameters
public function testGroupRoutes()
{
$this->router->group('/user', function(Router $router) {
$router->map('/@id', function ($id) {
echo $id;
});
$router->map('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
$this->router->group('/user', function (Router $router) {
$router->map('/@id', function ($id) {
echo $id;
});
$router->map('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
$this->request->url = '/user/123';
$this->check('123');
}
public function testGroupRoutesMultiParams()
public function testGroupRoutesMultiParams()
{
$this->router->group('/user', function(Router $router) {
$router->map('/@id', function ($id) {
echo $id;
});
$router->map('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
$this->router->group('/user', function (Router $router) {
$router->map('/@id', function ($id) {
echo $id;
});
$router->map('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
$this->request->url = '/user/123/abc';
$this->check('123abc');
}
public function testGroupNestedRoutes()
public function testGroupNestedRoutes()
{
$this->router->group('/client', function(Router $router) {
$router->group('/user', function(Router $router) {
$router->map('/@id', function ($id) {
echo $id;
});
$router->map('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
});
$this->router->group('/client', function (Router $router) {
$router->group('/user', function (Router $router) {
$router->map('/@id', function ($id) {
echo $id;
});
$router->map('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
});
$this->request->url = '/client/user/123/abc';
$this->check('123abc');
}
public function testGroupNestedRoutesWithCustomMethods()
public function testGroupNestedRoutesWithCustomMethods()
{
$this->router->group('/client', function(Router $router) {
$router->group('/user', function(Router $router) {
$router->get('/@id', function ($id) {
echo $id;
});
$router->post('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
});
$this->router->group('/client', function (Router $router) {
$router->group('/user', function (Router $router) {
$router->get('/@id', function ($id) {
echo $id;
});
$router->post('/@id/@name', function ($id, $name) {
echo $id . $name;
});
});
});
$this->request->url = '/client/user/123/abc';
$this->request->method = 'POST';
$this->request->method = 'POST';
$this->check('123abc');
}
public function testGetUrlByAliasBadReferenceButCatchRecommendation() {
$this->router->map('/path1', [$this, 'ok'], false, 'path1');
$this->expectException(\Exception::class);
$this->expectExceptionMessage('No route found with alias: \'path2\'. Did you mean \'path1\'?');
$this->router->getUrlByAlias('path2');
}
public function testRewindAndValid() {
$this->router->map('/path1', [$this, 'ok']);
$this->router->map('/path2', [$this, 'ok']);
$this->router->map('/path3', [$this, 'ok']);
$this->router->next();
$this->router->next();
$result = $this->router->valid();
$this->assertTrue($result);
$this->router->next();
$result = $this->router->valid();
$this->assertFalse($result);
$this->router->rewind();
$result = $this->router->valid();
$this->assertTrue($result);
}
public function testGetUrlByAliasNoMatches() {
$this->router->map('/path1', [$this, 'ok'], false, 'path1');
$this->expectException(\Exception::class);
$this->expectExceptionMessage('No route found with alias: \'path2\'');
$this->router->getUrlByAlias('path2');
}
public function testGetUrlByAliasNoParams() {
$this->router->map('/path1', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasSimpleParams() {
$this->router->map('/path1/@id', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleParamsWithNumber() {
$this->router->map('/path1/@id1', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id1' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsWithParam() {
$this->router->map('/path1(/@id)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsWithNumberWithParam() {
$this->router->map('/path1(/@id1)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id1' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsNoParam() {
$this->router->map('/path1(/@id)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsWithNumberNoParam() {
$this->router->map('/path1(/@id1)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasMultipleParams() {
$this->router->map('/path1/@id/@name', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => 123, 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexParams() {
$this->router->map('/path1/@id:[0-9]+/@name:[a-zA-Z0-9]{5}', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => '123', 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexParamsWithNumbers() {
$this->router->map('/path1/@5id:[0-9]+/@n1ame:[a-zA-Z0-9]{5}', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['5id' => '123', 'n1ame' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexOptionalParamsMissingOne() {
$this->router->map('/path1(/@id:[0-9]+(/@name(/@crazy:[a-z]{5})))', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => '123', 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexOptionalParamsAllParams() {
$this->router->map('/path1(/@id:[0-9]+(/@name(/@crazy:[a-z]{5})))', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => '123', 'name' => 'abc', 'crazy' => 'xyz']);
$this->assertEquals('/path1/123/abc/xyz', $url);
}
public function testGetUrlByAliasMultipleComplexOptionalParamsNoParams() {
$this->router->map('/path1(/@id:[0-9]+(/@name(/@crazy:[a-z]{5})))', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasWithGroupSimpleParams() {
$this->router->group('/path1/@id', function($router) {
$router->get('/@name', [$this, 'ok'], false, 'path1');
});
$url = $this->router->getUrlByAlias('path1', ['id' => 123, 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasBadReferenceButCatchRecommendation()
{
$this->router->map('/path1', [$this, 'ok'], false, 'path1');
$this->expectException(\Exception::class);
$this->expectExceptionMessage('No route found with alias: \'path2\'. Did you mean \'path1\'?');
$this->router->getUrlByAlias('path2');
}
public function testRewindAndValid()
{
$this->router->map('/path1', [$this, 'ok']);
$this->router->map('/path2', [$this, 'ok']);
$this->router->map('/path3', [$this, 'ok']);
$this->router->next();
$this->router->next();
$result = $this->router->valid();
$this->assertTrue($result);
$this->router->next();
$result = $this->router->valid();
$this->assertFalse($result);
$this->router->rewind();
$result = $this->router->valid();
$this->assertTrue($result);
}
public function testGetUrlByAliasNoMatches()
{
$this->router->map('/path1', [$this, 'ok'], false, 'path1');
$this->expectException(\Exception::class);
$this->expectExceptionMessage('No route found with alias: \'path2\'');
$this->router->getUrlByAlias('path2');
}
public function testGetUrlByAliasNoParams()
{
$this->router->map('/path1', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasSimpleParams()
{
$this->router->map('/path1/@id', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleParamsWithNumber()
{
$this->router->map('/path1/@id1', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id1' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsWithParam()
{
$this->router->map('/path1(/@id)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsWithNumberWithParam()
{
$this->router->map('/path1(/@id1)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id1' => 123]);
$this->assertEquals('/path1/123', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsNoParam()
{
$this->router->map('/path1(/@id)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasSimpleOptionalParamsWithNumberNoParam()
{
$this->router->map('/path1(/@id1)', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasMultipleParams()
{
$this->router->map('/path1/@id/@name', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => 123, 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexParams()
{
$this->router->map('/path1/@id:[0-9]+/@name:[a-zA-Z0-9]{5}', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => '123', 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexParamsWithNumbers()
{
$this->router->map('/path1/@5id:[0-9]+/@n1ame:[a-zA-Z0-9]{5}', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['5id' => '123', 'n1ame' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexOptionalParamsMissingOne()
{
$this->router->map('/path1(/@id:[0-9]+(/@name(/@crazy:[a-z]{5})))', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => '123', 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
public function testGetUrlByAliasMultipleComplexOptionalParamsAllParams()
{
$this->router->map('/path1(/@id:[0-9]+(/@name(/@crazy:[a-z]{5})))', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1', ['id' => '123', 'name' => 'abc', 'crazy' => 'xyz']);
$this->assertEquals('/path1/123/abc/xyz', $url);
}
public function testGetUrlByAliasMultipleComplexOptionalParamsNoParams()
{
$this->router->map('/path1(/@id:[0-9]+(/@name(/@crazy:[a-z]{5})))', [$this, 'ok'], false, 'path1');
$url = $this->router->getUrlByAlias('path1');
$this->assertEquals('/path1', $url);
}
public function testGetUrlByAliasWithGroupSimpleParams()
{
$this->router->group('/path1/@id', function ($router) {
$router->get('/@name', [$this, 'ok'], false, 'path1');
});
$url = $this->router->getUrlByAlias('path1', ['id' => 123, 'name' => 'abc']);
$this->assertEquals('/path1/123/abc', $url);
}
}

@ -1,4 +1,5 @@
<?php
/**
* Flight: An extensible micro-framework.
*

@ -36,20 +36,21 @@ class ViewTest extends PHPUnit\Framework\TestCase
$this->assertNull($this->view->get('test'));
}
public function testMultipleVariables() {
$this->view->set([
'test' => 123,
'foo' => 'bar'
]);
public function testMultipleVariables()
{
$this->view->set([
'test' => 123,
'foo' => 'bar'
]);
$this->assertEquals(123, $this->view->get('test'));
$this->assertEquals('bar', $this->view->get('foo'));
$this->assertEquals(123, $this->view->get('test'));
$this->assertEquals('bar', $this->view->get('foo'));
$this->view->clear();
$this->view->clear();
$this->assertNull($this->view->get('test'));
$this->assertNull($this->view->get('foo'));
}
$this->assertNull($this->view->get('test'));
$this->assertNull($this->view->get('foo'));
}
// Check if template files exist
public function testTemplateExists()
@ -66,12 +67,13 @@ class ViewTest extends PHPUnit\Framework\TestCase
$this->expectOutputString('Hello, Bob!');
}
public function testRenderBadFilePath() {
$this->expectException(Exception::class);
$this->expectExceptionMessage('Template file not found: ' . __DIR__ . DIRECTORY_SEPARATOR . 'views'. DIRECTORY_SEPARATOR . 'badfile.php');
public function testRenderBadFilePath()
{
$this->expectException(Exception::class);
$this->expectExceptionMessage('Template file not found: ' . __DIR__ . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'badfile.php');
$this->view->render('badfile');
}
$this->view->render('badfile');
}
// Fetch template output
public function testFetch()
@ -102,24 +104,27 @@ class ViewTest extends PHPUnit\Framework\TestCase
$this->expectOutputString('Hello world, Bob!');
}
public function testGetTemplateAbsolutePath() {
$tmpfile = tmpfile();
$this->view->extension = '';
$file_path = stream_get_meta_data($tmpfile)['uri'];
$this->assertEquals($file_path, $this->view->getTemplate($file_path));
}
public function testE() {
$this->expectOutputString('&lt;script&gt;');
$result = $this->view->e('<script>');
$this->assertEquals('&lt;script&gt;', $result);
}
public function testENoNeedToEscape() {
$this->expectOutputString('script');
$result = $this->view->e('script');
$this->assertEquals('script', $result);
}
public function testGetTemplateAbsolutePath()
{
$tmpfile = tmpfile();
$this->view->extension = '';
$file_path = stream_get_meta_data($tmpfile)['uri'];
$this->assertEquals($file_path, $this->view->getTemplate($file_path));
}
public function testE()
{
$this->expectOutputString('&lt;script&gt;');
$result = $this->view->e('<script>');
$this->assertEquals('&lt;script&gt;', $result);
}
public function testENoNeedToEscape()
{
$this->expectOutputString('script');
$result = $this->view->e('script');
$this->assertEquals('script', $result);
}
public function testNormalizePath(): void
{

@ -1,17 +1,20 @@
<?php
class TesterClass {
public $param1;
public $param2;
public $param3;
public $param4;
public $param5;
public $param6;
public function __construct($param1, $param2, $param3, $param4, $param5, $param6) {
$this->param1 = $param1;
$this->param2 = $param2;
$this->param3 = $param3;
$this->param4 = $param4;
$this->param5 = $param5;
$this->param6 = $param6;
}
};
class TesterClass
{
public $param1;
public $param2;
public $param3;
public $param4;
public $param5;
public $param6;
public function __construct($param1, $param2, $param3, $param4, $param5, $param6)
{
$this->param1 = $param1;
$this->param2 = $param2;
$this->param3 = $param3;
$this->param4 = $param4;
$this->param5 = $param5;
$this->param6 = $param6;
}
};

@ -1,6 +1,6 @@
<?php
$path = file_exists(__DIR__ . '/../vendor/autoload.php')
? __DIR__ . '/../vendor/autoload.php'
: __DIR__ . '/../flight/autoload.php';
require_once($path);
? __DIR__ . '/../vendor/autoload.php'
: __DIR__ . '/../flight/autoload.php';
require_once($path);

Loading…
Cancel
Save