From cc4338a34b9b316052967768235ad6d8aa9f00ed Mon Sep 17 00:00:00 2001 From: Austin Collier Date: Wed, 24 Jan 2024 22:23:14 -0700 Subject: [PATCH] added PSR12 coding style to files. --- composer.json | 7 +- flight/Engine.php | 138 ++-- flight/Flight.php | 61 +- flight/autoload.php | 1 + flight/core/Dispatcher.php | 11 +- flight/core/Loader.php | 7 +- flight/database/PdoWrapper.php | 287 ++++---- flight/net/Request.php | 7 +- flight/net/Response.php | 32 +- flight/net/Route.php | 124 ++-- flight/net/Router.php | 293 +++++---- flight/template/View.php | 5 +- flight/util/Collection.php | 1 + flight/util/ReturnTypeWillChange.php | 4 +- phpcs.xml | 10 + tests/AutoloadTest.php | 1 + tests/CollectionTest.php | 154 ++--- tests/DispatcherTest.php | 128 ++-- tests/EngineTest.php | 939 +++++++++++++++------------ tests/FilterTest.php | 1 + tests/FlightTest.php | 271 ++++---- tests/LoaderTest.php | 67 +- tests/MapTest.php | 1 + tests/PdoWrapperTest.php | 179 ++--- tests/RedirectTest.php | 1 + tests/RegisterTest.php | 1 + tests/RenderTest.php | 1 + tests/RequestTest.php | 91 +-- tests/ResponseTest.php | 417 ++++++------ tests/RouterTest.php | 535 +++++++-------- tests/VariableTest.php | 1 + tests/ViewTest.php | 73 ++- tests/classes/TesterClass.php | 35 +- tests/phpunit_autoload.php | 6 +- 34 files changed, 2071 insertions(+), 1819 deletions(-) create mode 100644 phpcs.xml diff --git a/composer.json b/composer.json index 22d6e6e..60b0ed7 100644 --- a/composer.json +++ b/composer.json @@ -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", diff --git a/flight/Engine.php b/flight/Engine.php index 0475460..2f9aac5 100644 --- a/flight/Engine.php +++ b/flight/Engine.php @@ -1,6 +1,7 @@ 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 $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 $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 $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 $params The params for the route if applicable. + */ + public function _getUrl(string $alias, array $params = []): string + { + return $this->router()->getUrlByAlias($alias, $params); + } } diff --git a/flight/Flight.php b/flight/Flight.php index 25d650a..f34c975 100644 --- a/flight/Flight.php +++ b/flight/Flight.php @@ -1,6 +1,7 @@ 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(); } /** diff --git a/flight/core/Loader.php b/flight/core/Loader.php index 8dbf843..b4e8efa 100644 --- a/flight/core/Loader.php +++ b/flight/core/Loader.php @@ -1,6 +1,7 @@ $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 $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 $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 $params - Ex: [ $something ] - * @return array - */ - 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 $params - Ex: [ $something ] - * @return array> - */ - 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 $params the params for the sql statement - * @return array> - */ - 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 ]; - } -} \ No newline at end of file +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 $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 $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 $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 $params - Ex: [ $something ] + * @return array + */ + 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 $params - Ex: [ $something ] + * @return array> + */ + 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 $params the params for the sql statement + * @return array> + */ + 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 ]; + } +} diff --git a/flight/net/Request.php b/flight/net/Request.php index 2a76f54..846896a 100644 --- a/flight/net/Request.php +++ b/flight/net/Request.php @@ -1,6 +1,7 @@ base && '' !== $this->base && 0 === strpos($this->url, $this->base)) { $this->url = substr($this->url, \strlen($this->base)); } diff --git a/flight/net/Response.php b/flight/net/Response.php index 6b2c863..8f290dd 100644 --- a/flight/net/Response.php +++ b/flight/net/Response.php @@ -1,6 +1,7 @@ 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. diff --git a/flight/net/Route.php b/flight/net/Route.php index 6afcd35..cdf67ef 100644 --- a/flight/net/Route.php +++ b/flight/net/Route.php @@ -1,6 +1,7 @@ The middleware to be applied to the route - */ - public array $middleware = []; + /** + * @var array 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 $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|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 $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|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; + } } diff --git a/flight/net/Router.php b/flight/net/Router.php index 1849e9b..5c4e99b 100644 --- a/flight/net/Router.php +++ b/flight/net/Router.php @@ -1,6 +1,7 @@ - */ - protected array $group_middlewares = []; + /** + * Group Middleware + * + * @var array + */ + 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 $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 $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 $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 $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. diff --git a/flight/template/View.php b/flight/template/View.php index 6207288..7d08623 100644 --- a/flight/template/View.php +++ b/flight/template/View.php @@ -1,6 +1,7 @@ + + Created with the PHP Coding Standard Generator. http://edorian.github.io/php-coding-standard-generator/ + + + + + flight/ + tests/ + \ No newline at end of file diff --git a/tests/AutoloadTest.php b/tests/AutoloadTest.php index 993659b..ff44485 100644 --- a/tests/AutoloadTest.php +++ b/tests/AutoloadTest.php @@ -1,4 +1,5 @@ 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()); + } } diff --git a/tests/DispatcherTest.php b/tests/DispatcherTest.php index 0fc5d47..cb8edf9 100644 --- a/tests/DispatcherTest.php +++ b/tests/DispatcherTest.php @@ -1,4 +1,5 @@ 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); + } } diff --git a/tests/EngineTest.php b/tests/EngineTest.php index 3f5b2f5..012c472 100644 --- a/tests/EngineTest.php +++ b/tests/EngineTest.php @@ -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('

500 Internal Server Error

thrown exception message (20)

'); - $this->expectOutputRegex('~'.$regex_message.'~'); - $engine->handleException(new Exception('thrown exception message', 20)); - } - - public function testMapExistingMethod() { - $engine = new Engine(); - $this->expectException(Exception::class); - $this->expectExceptionMessage('Cannot override an existing framework method.'); - $engine->map('_start', function() {}); - } - - public function testRegisterExistingMethod() { - $engine = new Engine(); - $this->expectException(Exception::class); - $this->expectExceptionMessage('Cannot override an existing framework method.'); - $engine->register('_error', 'stdClass'); - } - - public function testSetArrayOfValues() { - $engine = new Engine(); - $engine->set([ 'key1' => 'value1', 'key2' => 'value2']); - $this->assertEquals('value1', $engine->get('key1')); - $this->assertEquals('value2', $engine->get('key2')); - } - - public function testStartWithRoute() { - $_SERVER['REQUEST_METHOD'] = 'GET'; - $_SERVER['REQUEST_URI'] = '/someRoute'; - - $engine = new class extends Engine { - public function getInitializedVar() { - return $this->initialized; - } - }; - $engine->route('/someRoute', function() { echo 'i ran'; }, true); - $this->expectOutputString('i ran'); - $engine->start(); - } - - // n0nag0n - I don't know why this does what it does, but it's existing framework functionality 1/1/24 - public function testStartWithRouteButReturnedValueThrows404() { - $_SERVER['REQUEST_METHOD'] = 'GET'; - $_SERVER['REQUEST_URI'] = '/someRoute'; - - $engine = new class extends Engine { - public function getInitializedVar() { - return $this->initialized; - } - }; - $engine->route('/someRoute', function() { echo 'i ran'; return true; }, true); - $this->expectOutputString('

404 Not Found

The page you have requested could not be found.

'); - $engine->start(); - } - - public function testStopWithCode() { - $engine = new class extends Engine { - public function getLoader() { - return $this->loader; - } - }; - // doing this so we can overwrite some parts of the response - $engine->getLoader()->register('response', function() { - return new class extends 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('

500 Internal Server Error

thrown exception message (20)

'); + $this->expectOutputRegex('~' . $regex_message . '~'); + $engine->handleException(new Exception('thrown exception message', 20)); + } + + public function testMapExistingMethod() + { + $engine = new Engine(); + $this->expectException(Exception::class); + $this->expectExceptionMessage('Cannot override an existing framework method.'); + $engine->map('_start', function () { + }); + } + + public function testRegisterExistingMethod() + { + $engine = new Engine(); + $this->expectException(Exception::class); + $this->expectExceptionMessage('Cannot override an existing framework method.'); + $engine->register('_error', 'stdClass'); + } + + public function testSetArrayOfValues() + { + $engine = new Engine(); + $engine->set([ 'key1' => 'value1', 'key2' => 'value2']); + $this->assertEquals('value1', $engine->get('key1')); + $this->assertEquals('value2', $engine->get('key2')); + } + + public function testStartWithRoute() + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/someRoute'; + + $engine = new class extends Engine { + public function getInitializedVar() + { + return $this->initialized; + } + }; + $engine->route('/someRoute', function () { + echo 'i ran'; + }, true); + $this->expectOutputString('i ran'); + $engine->start(); + } + + // n0nag0n - I don't know why this does what it does, but it's existing framework functionality 1/1/24 + public function testStartWithRouteButReturnedValueThrows404() + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_SERVER['REQUEST_URI'] = '/someRoute'; + + $engine = new class extends Engine { + public function getInitializedVar() + { + return $this->initialized; + } + }; + $engine->route('/someRoute', function () { + echo 'i ran'; + return true; + }, true); + $this->expectOutputString('

404 Not Found

The page you have requested could not be found.

'); + $engine->start(); + } + + public function testStopWithCode() + { + $engine = new class extends Engine { + public function getLoader() + { + return $this->loader; + } + }; + // doing this so we can overwrite some parts of the response + $engine->getLoader()->register('response', function () { + return new class extends 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'); + } } diff --git a/tests/FilterTest.php b/tests/FilterTest.php index 9681a62..fbf27e0 100644 --- a/tests/FilterTest.php +++ b/tests/FilterTest.php @@ -1,4 +1,5 @@ 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); + } } diff --git a/tests/LoaderTest.php b/tests/LoaderTest.php index 6c89a82..b4f7d4d 100644 --- a/tests/LoaderTest.php +++ b/tests/LoaderTest.php @@ -1,4 +1,5 @@ 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()); + } } diff --git a/tests/MapTest.php b/tests/MapTest.php index 4f4a0eb..d147c94 100644 --- a/tests/MapTest.php +++ b/tests/MapTest.php @@ -1,4 +1,5 @@ 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)); + } } diff --git a/tests/RedirectTest.php b/tests/RedirectTest.php index 9099fe4..758df92 100644 --- a/tests/RedirectTest.php +++ b/tests/RedirectTest.php @@ -1,4 +1,5 @@ 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()); + } } diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php index bbcdb62..75c55b2 100644 --- a/tests/ResponseTest.php +++ b/tests/ResponseTest.php @@ -1,4 +1,5 @@ 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()); + } } diff --git a/tests/RouterTest.php b/tests/RouterTest.php index c7db9e3..8697a91 100644 --- a/tests/RouterTest.php +++ b/tests/RouterTest.php @@ -1,4 +1,5 @@ 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); + } } diff --git a/tests/VariableTest.php b/tests/VariableTest.php index 03f2900..8bc7462 100644 --- a/tests/VariableTest.php +++ b/tests/VariableTest.php @@ -1,4 +1,5 @@ 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('<script>'); - $result = $this->view->e('