diff options
author | msquare <msquare@notrademark.de> | 2017-11-12 13:25:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-12 13:25:56 +0100 |
commit | ebc973bf221bfbde327868975221e62704e4cb99 (patch) | |
tree | 9011a160f3d6f9cae37fc02836e7d6e8c25242ca | |
parent | 801c17aa6cef91be988a25a90442be8d2078a70d (diff) | |
parent | ad948bdd3201e922b626a736b0122533bdd37cae (diff) |
Merge pull request #349 from MyIgel/master
Changed container to Illuminate/Container and added service providers
54 files changed, 1668 insertions, 410 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..1cc9797b --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,90 @@ +image: php + +cache: + paths: + - .composer + +services: + - mysql:5.6 + +variables: + MYSQL_DATABASE: engelsystem + MYSQL_USER: engel + MYSQL_PASSWORD: engelsystem + COMPOSER_HOME: .composer + MYSQL_RANDOM_ROOT_PASSWORD: "yes" + +before_script: + # Fix permissions after gitlab messed them up + - find . -type f -exec chmod 644 {} \; + - find . -type d -exec chmod 755 {} \; + # Install required Packages + - apt update -yqq + - apt install -yqq git unzip mysql-client + - docker-php-ext-install pdo pdo_mysql gettext + # Install xdebug + - pecl install xdebug + - docker-php-ext-enable xdebug + # MySQL DB + - mysql -h mysql -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < db/install.sql + - mysql -h mysql -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" < db/update.sql + # Install Composer + - curl -sS https://getcomposer.org/installer | php -- --no-ansi --install-dir /usr/local/bin/ --filename composer + - /usr/local/bin/composer --no-ansi install + +.test_template: &test_definition + artifacts: + name: "${CI_JOB_NAME}_${CI_PROJECT_ID}_${PHP_VERSION}" + expire_in: 1 week + paths: + - ./coverage/ + coverage: '/^\s*Lines:\s*(\d+(?:\.\d+)?%)/' + script: vendor/bin/phpunit --colors=never --coverage-text --coverage-html ./coverage/ + +test:7.0: + image: php:7.0 + <<: *test_definition + +test:7.1: + image: php:7.1 + <<: *test_definition + +deploy_staging: + stage: deploy + only: + - master + script: + - |- + if [ -z "${SSH_PRIVATE_KEY}" ] || [ -z "${REMOTE}" ] || [ -z "${REMOTE_PATH}" ]; then + echo "Skipping deployment"; + exit + fi + - mkdir -p ~/.ssh + - echo "$SSH_PRIVATE_KEY" | sed -e 's/\r//g' > ~/.ssh/id_ed25519 + - chmod 600 ~/.ssh/id_ed25519 + - apt update && apt install -yqq rsync openssh-client + - /usr/local/bin/composer --no-ansi install --no-dev + - /usr/local/bin/composer --no-ansi dump-autoload --optimize + - echo "syncing ${PWD}/ to ${REMOTE}:${REMOTE_PATH}/${CI_JOB_ID}-${CI_COMMIT_SHA}/" + - |- + rsync -vAax --exclude '.git*' --exclude .composer/ \ + -e "ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" \ + ./ "${REMOTE}:${REMOTE_PATH}/${CI_JOB_ID}-${CI_COMMIT_SHA}/" + - |- + ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${REMOTE}" " + set -e + + if [[ -f \"${REMOTE_PATH}/current/config/config.php\" ]]; then + echo \"Config backup\" + cp \"${REMOTE_PATH}/current/config/config.php\" config.php + fi + + echo \"Changing symlink\" + unlink \"${REMOTE_PATH}/current\" + ln -s \"${REMOTE_PATH}/${CI_JOB_ID}-${CI_COMMIT_SHA}\" \"${REMOTE_PATH}/current\" + + if [[ -f config.php ]]; then + echo \"Restoring config\" + cp config.php \"${REMOTE_PATH}/current/config/config.php\" + fi + " diff --git a/composer.json b/composer.json index 35956e20..a8f0b0d6 100644 --- a/composer.json +++ b/composer.json @@ -15,11 +15,12 @@ ], "require": { "php": ">=7.0.0", - "erusev/parsedown": "1.6.*", - "twbs/bootstrap": "^3.3", - "symfony/http-foundation": "^3.3", + "erusev/parsedown": "^1.6", + "illuminate/container": "5.5.*", "psr/container": "^1.0", - "psr/log": "^1.0" + "psr/log": "^1.0", + "symfony/http-foundation": "^3.3", + "twbs/bootstrap": "^3.3" }, "require-dev": { "phpunit/phpunit": "^6.3" diff --git a/config/app.php b/config/app.php new file mode 100644 index 00000000..74eb2991 --- /dev/null +++ b/config/app.php @@ -0,0 +1,17 @@ +<?php + +// Application config + +return [ + // Service providers + 'providers' => [ + \Engelsystem\Logger\LoggerServiceProvider::class, + \Engelsystem\Exceptions\ExceptionsServiceProvider::class, + \Engelsystem\Config\ConfigServiceProvider::class, + \Engelsystem\Routing\RoutingServiceProvider::class, + \Engelsystem\Renderer\RendererServiceProvider::class, + \Engelsystem\Database\DatabaseServiceProvider::class, + \Engelsystem\Http\RequestServiceProvider::class, + \Engelsystem\Http\SessionServiceProvider::class, + ], +]; diff --git a/config/config.default.php b/config/config.default.php index c2d742ef..1bad9668 100644 --- a/config/config.default.php +++ b/config/config.default.php @@ -5,10 +5,10 @@ return [ // MySQL-Connection Settings 'database' => [ - 'host' => 'localhost', - 'user' => 'root', - 'pw' => '', - 'db' => 'engelsystem', + 'host' => env('MYSQL_HOST', (env('CI', false) ? 'mysql' : 'localhost')), + 'user' => env('MYSQL_USER', 'root'), + 'pw' => env('MYSQL_PASSWORD', ''), + 'db' => env('MYSQL_DATABASE', 'engelsystem'), ], // For accessing stats diff --git a/db/install.sql b/db/install.sql index 0222dc08..3c3e41e6 100644 --- a/db/install.sql +++ b/db/install.sql @@ -205,7 +205,7 @@ DROP TABLE IF EXISTS `NewsComments`; CREATE TABLE `NewsComments` ( `ID` bigint(11) NOT NULL, `Refid` int(11) NOT NULL DEFAULT '0', - `Datum` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `Datum` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `Text` text NOT NULL, `UID` int(11) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -395,7 +395,7 @@ CREATE TABLE `User` ( `Sprache` char(64) NOT NULL, `Menu` char(1) NOT NULL DEFAULT 'L', `lastLogIn` int(11) NOT NULL, - `CreateDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `CreateDate` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `Art` varchar(30) DEFAULT NULL, `kommentar` text, `Hometown` varchar(255) NOT NULL DEFAULT '', diff --git a/includes/autoload.php b/includes/autoload.php index f51f89e4..0cd9d355 100644 --- a/includes/autoload.php +++ b/includes/autoload.php @@ -6,4 +6,4 @@ if (!is_readable(__DIR__ . '/../vendor/autoload.php')) { } // Include composer autoloader -require_once __DIR__ . '/../vendor/autoload.php'; +$loader = require __DIR__ . '/../vendor/autoload.php'; diff --git a/includes/engelsystem.php b/includes/engelsystem.php new file mode 100644 index 00000000..97076895 --- /dev/null +++ b/includes/engelsystem.php @@ -0,0 +1,61 @@ +<?php + +use Engelsystem\Application; +use Engelsystem\Config\Config; +use Engelsystem\Exceptions\Handler as ExceptionHandler; + +/** + * This file includes all needed functions, connects to the db etc. + */ +require_once __DIR__ . '/autoload.php'; + + +/** + * Include legacy code + */ +require __DIR__ . '/includes.php'; + + +/** + * Initialize and bootstrap the application + */ +$app = new Application(realpath(__DIR__ . DIRECTORY_SEPARATOR . '..')); +$appConfig = $app->make(Config::class); +$appConfig->set(require config_path('app.php')); +$app->bootstrap($appConfig); + + +/** + * Configure application + */ +date_default_timezone_set($app->get('config')->get('timezone')); + +if (config('environment') == 'development') { + $errorHandler = $app->get('error.handler'); + $errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT); + ini_set('display_errors', true); + error_reporting(E_ALL); +} else { + ini_set('display_errors', false); +} + + +/** + * Check for maintenance + */ +if ($app->get('config')->get('maintenance')) { + echo file_get_contents(__DIR__ . '/../templates/maintenance.html'); + die(); +} + + +/** + * Init translations + */ +gettext_init(); + + +/** + * Init authorization + */ +load_auth(); diff --git a/includes/helper/internationalization_helper.php b/includes/helper/internationalization_helper.php index efbe5db5..7fa6518b 100644 --- a/includes/helper/internationalization_helper.php +++ b/includes/helper/internationalization_helper.php @@ -36,7 +36,7 @@ function gettext_init() } gettext_locale(); - bindtextdomain('default', realpath(__DIR__ . '/../../locale')); + bindtextdomain('default', app('path.lang')); bind_textdomain_codeset('default', 'UTF-8'); textdomain('default'); } diff --git a/includes/engelsystem_provider.php b/includes/includes.php index 0de5e0f5..a42f960f 100644 --- a/includes/engelsystem_provider.php +++ b/includes/includes.php @@ -1,115 +1,5 @@ <?php -use Engelsystem\Application; -use Engelsystem\Config\Config; -use Engelsystem\Database\Db; -use Engelsystem\Exceptions\Handler as ExceptionHandler; -use Engelsystem\Http\Request; -use Engelsystem\Logger\EngelsystemLogger; -use Engelsystem\Renderer\HtmlEngine; -use Engelsystem\Renderer\Renderer; -use Engelsystem\Routing\UrlGenerator; -use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; -use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; - -/** - * This file includes all needed functions, connects to the db etc. - */ -require_once __DIR__ . '/autoload.php'; - - -/** - * Initialize the application - */ -$app = Application::getInstance(); - - -/** - * Load configuration - */ -$config = new Config(); -$app->instance('config', $config); -$config->set(require __DIR__ . '/../config/config.default.php'); - -if (file_exists(__DIR__ . '/../config/config.php')) { - $config->set(array_replace_recursive( - $config->get(null), - require __DIR__ . '/../config/config.php' - )); -} - -date_default_timezone_set($config->get('timezone')); - - -/** - * Initialize Request - * - * @var Request $request - */ -$request = Request::createFromGlobals(); -$app->instance('request', $request); - - -/** - * Check for maintenance - */ -if ($config->get('maintenance')) { - echo file_get_contents(__DIR__ . '/../templates/maintenance.html'); - die(); -} - - -/** - * Register UrlGenerator - */ -$urlGenerator = new UrlGenerator(); -$app->instance('routing.urlGenerator', $urlGenerator); - - -/** - * Initialize renderer - */ -$renderer = new Renderer(); -$app->instance('renderer', $renderer); -$renderer->addRenderer(new HtmlEngine()); - - -/** - * Register error handler - */ -$errorHandler = new ExceptionHandler(); -$app->instance('error.handler', $errorHandler); -if (config('environment') == 'development') { - $errorHandler->setEnvironment(ExceptionHandler::ENV_DEVELOPMENT); - ini_set('display_errors', true); - error_reporting(E_ALL); -} else { - ini_set('display_errors', false); -} - - -/** - * Connect to database - */ -Db::connect( - 'mysql:host=' . config('database')['host'] . ';dbname=' . config('database')['db'] . ';charset=utf8', - config('database')['user'], - config('database')['pw'] -) || die('Error: Unable to connect to database'); -Db::getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); -Db::getPdo()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); - -/** - * Init logger - */ -$logger = new EngelsystemLogger(); -$app->instance('logger', $logger); -$app->instance(LoggerInterface::class, $logger); -$app->instance(EngelsystemLogger::class, $logger); - - /** * Include legacy code */ @@ -194,17 +84,3 @@ $includeFiles = [ foreach ($includeFiles as $file) { require_once realpath($file); } - - -/** - * Init application - */ -$sessionStorage = (PHP_SAPI != 'cli' ? new NativeSessionStorage(['cookie_httponly' => true]) : new MockArraySessionStorage()); -$session = new Session($sessionStorage); -$app->instance('session', $session); -$session->start(); -$request->setSession($session); - -gettext_init(); - -load_auth(); diff --git a/includes/model/Shifts_model.php b/includes/model/Shifts_model.php index 03f8341f..ef02aaab 100644 --- a/includes/model/Shifts_model.php +++ b/includes/model/Shifts_model.php @@ -481,9 +481,10 @@ function Shift_create($shift) `URL`, `PSID`, `created_by_user_id`, + `edited_at_timestamp`, `created_at_timestamp` ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ', [ $shift['shifttype_id'], @@ -495,6 +496,7 @@ function Shift_create($shift) $shift['PSID'], $user['UID'], time(), + time(), ] ); diff --git a/includes/model/UserAngelTypes_model.php b/includes/model/UserAngelTypes_model.php index 5b0caf98..0c413010 100644 --- a/includes/model/UserAngelTypes_model.php +++ b/includes/model/UserAngelTypes_model.php @@ -59,7 +59,7 @@ function User_unconfirmed_AngelTypes($user) AND `UserAngelTypes`.`supporter`=TRUE AND `AngelTypes`.`restricted`=TRUE AND `UnconfirmedMembers`.`confirm_user_id` IS NULL - GROUP BY `UserAngelTypes`.`angeltype_id` + GROUP BY `UserAngelTypes`.`angeltype_id`, `UserAngelTypes`.`id` ORDER BY `AngelTypes`.`name` ', [$user['UID']]); } diff --git a/includes/pages/user_shifts.php b/includes/pages/user_shifts.php index 2bd7688f..24b9251a 100644 --- a/includes/pages/user_shifts.php +++ b/includes/pages/user_shifts.php @@ -109,7 +109,7 @@ function load_days() $days = DB::select(' SELECT DISTINCT DATE(FROM_UNIXTIME(`start`)) AS `id`, DATE(FROM_UNIXTIME(`start`)) AS `name` FROM `Shifts` - ORDER BY `start` + ORDER BY `id`, `name` '); $days = array_map('array_shift', $days); diff --git a/phpunit.xml b/phpunit.xml index bdc4b0b6..98e64795 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,5 @@ <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - bootstrap="./includes/autoload.php" + bootstrap="./tests/autoload.php" xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.3/phpunit.xsd" colors="true" > @@ -13,7 +13,6 @@ </testsuites> <filter> <whitelist> - <directory>./include/</directory> <directory>./src/</directory> </whitelist> </filter> diff --git a/public/index.php b/public/index.php index c65dbdf8..69d92127 100644 --- a/public/index.php +++ b/public/index.php @@ -1,6 +1,8 @@ <?php -require_once realpath(__DIR__ . '/../includes/engelsystem_provider.php'); +use Engelsystem\Http\Request; + +require_once realpath(__DIR__ . '/../includes/engelsystem.php'); $free_pages = [ 'admin_event_config', @@ -25,6 +27,8 @@ $page = ''; $title = ''; $content = ''; +/** @var Request $request */ +$request = $app->get('request'); $page = $request->query->get('p'); if (empty($page)) { $page = $request->path(); diff --git a/src/Application.php b/src/Application.php index 674b3869..c9023c7b 100644 --- a/src/Application.php +++ b/src/Application.php @@ -2,24 +2,136 @@ namespace Engelsystem; +use Engelsystem\Config\Config; use Engelsystem\Container\Container; +use Engelsystem\Container\ServiceProvider; use Psr\Container\ContainerInterface; class Application extends Container { - public function __construct() + /** @var string|null */ + protected $appPath = null; + + /** @var bool */ + protected $isBootstrapped = false; + + /** + * Registered service providers + * + * @var array + */ + protected $serviceProviders = []; + + /** + * Application constructor. + * + * @param string $appPath + */ + public function __construct($appPath = null) { + if (!is_null($appPath)) { + $this->setAppPath($appPath); + } + $this->registerBaseBindings(); } protected function registerBaseBindings() { - self::setInstance($this); + static::setInstance($this); Container::setInstance($this); $this->instance('app', $this); $this->instance('container', $this); $this->instance(Container::class, $this); $this->instance(Application::class, $this); - $this->instance(ContainerInterface::class, $this); + $this->bind(ContainerInterface::class, Application::class); + } + + /** + * @param string|ServiceProvider $provider + * @return ServiceProvider + */ + public function register($provider) + { + if (is_string($provider)) { + $provider = $this->make($provider); + } + + $this->serviceProviders[] = $provider; + + $provider->register(); + + if ($this->isBootstrapped) { + $this->call([$provider, 'boot']); + } + + return $provider; + } + + /** + * Boot service providers + * + * @param Config|null $config + */ + public function bootstrap(Config $config = null) + { + if ($this->isBootstrapped) { + return; + } + + if ($config instanceof Config) { + foreach ($config->get('providers', []) as $provider) { + $this->register($provider); + } + } + + foreach ($this->serviceProviders as $provider) { + $this->call([$provider, 'boot']); + } + + $this->isBootstrapped = true; + } + + protected function registerPaths() + { + $appPath = $this->appPath; + + $this->instance('path', $appPath); + $this->instance('path.config', $appPath . DIRECTORY_SEPARATOR . 'config'); + $this->instance('path.lang', $appPath . DIRECTORY_SEPARATOR . 'locale'); + } + + /** + * Set app base path + * + * @param string $appPath + * @return static + */ + public function setAppPath($appPath) + { + $appPath = realpath($appPath); + $appPath = rtrim($appPath, DIRECTORY_SEPARATOR); + + $this->appPath = $appPath; + + $this->registerPaths(); + + return $this; + } + + /** + * @return string|null + */ + public function path() + { + return $this->appPath; + } + + /** + * @return bool + */ + public function isBooted() + { + return $this->isBootstrapped; } } diff --git a/src/Config/ConfigServiceProvider.php b/src/Config/ConfigServiceProvider.php new file mode 100644 index 00000000..01b648df --- /dev/null +++ b/src/Config/ConfigServiceProvider.php @@ -0,0 +1,26 @@ +<?php + +namespace Engelsystem\Config; + +use Engelsystem\Container\ServiceProvider; + +class ConfigServiceProvider extends ServiceProvider +{ + public function register() + { + $defaultConfigFile = config_path('config.default.php'); + $configFile = config_path('config.php'); + + $config = $this->app->make(Config::class); + $this->app->instance('config', $config); + + $config->set(require $defaultConfigFile); + + if (file_exists($configFile)) { + $config->set(array_replace_recursive( + $config->get(null), + require $configFile + )); + } + } +} diff --git a/src/Container/Container.php b/src/Container/Container.php index 59a17a04..44c57b6f 100644 --- a/src/Container/Container.php +++ b/src/Container/Container.php @@ -2,115 +2,9 @@ namespace Engelsystem\Container; -use Psr\Container\ContainerExceptionInterface; +use Illuminate\Container\Container as IlluminateContainer; use Psr\Container\ContainerInterface; -use Psr\Container\NotFoundExceptionInterface; -class Container implements ContainerInterface +class Container extends IlluminateContainer implements ContainerInterface { - /** - * The globally available container - * - * @var static - */ - protected static $instance; - - /** - * Contains the shared instances - * - * @var mixed[] - */ - protected $instances = []; - - /** - * Finds an entry of the container by its identifier and returns it - * - * @param string $id Identifier of the entry to look for - * - * @throws NotFoundExceptionInterface No entry was found for **this** identifier - * @throws ContainerExceptionInterface Error while retrieving the entry - * - * @return mixed Entry - */ - public function get($id) - { - if ($this->has($id)) { - return $this->resolve($id); - } - - throw new NotFoundException(sprintf('The entry with the id "%s" could not be found', $id)); - } - - /** - * Register a shared entry in the container - * - * @param string $abstract Identifier of the entry to set - * @param mixed $instance Entry - */ - public function instance($abstract, $instance) - { - $this->singleton($abstract, $instance); - } - - /** - * Register a shared entry as singleton in the container - * - * @param string $abstract - * @param mixed $instance - */ - public function singleton($abstract, $instance) - { - $this->instances[$abstract] = $instance; - } - - /** - * Returns true if the container can return an entry for the given identifier - * Returns false otherwise - * - * `has($id)` returning true does not mean that `get($id)` will not throw an exception - * It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface` - * - * @param string $id Identifier of the entry to look for - * - * @return bool - */ - public function has($id) - { - return isset($this->instances[$id]); - } - - /** - * Resolve the requested object - * - * @param string $abstract - * @return mixed - */ - protected function resolve($abstract) - { - return $this->instances[$abstract]; - } - - /** - * Get the globally available instance of the container - * - * @return self - */ - public static function getInstance() - { - if (is_null(static::$instance)) { - static::$instance = new static; - } - - return static::$instance; - } - - /** - * Set the globally available instance of the container - * - * @param Container $container - */ - public static function setInstance(Container $container) - { - static::$instance = $container; - } } diff --git a/src/Container/ContainerException.php b/src/Container/ContainerException.php deleted file mode 100644 index 3cdde506..00000000 --- a/src/Container/ContainerException.php +++ /dev/null @@ -1,11 +0,0 @@ -<?php - -namespace Engelsystem\Container; - -use Exception; -use Psr\Container\ContainerExceptionInterface; - -class ContainerException extends Exception implements ContainerExceptionInterface -{ - -} diff --git a/src/Container/NotFoundException.php b/src/Container/NotFoundException.php deleted file mode 100644 index a83be0b1..00000000 --- a/src/Container/NotFoundException.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -namespace Engelsystem\Container; - -use Psr\Container\NotFoundExceptionInterface; - -class NotFoundException extends ContainerException implements NotFoundExceptionInterface -{ - -} diff --git a/src/Container/ServiceProvider.php b/src/Container/ServiceProvider.php new file mode 100644 index 00000000..2a1bbebf --- /dev/null +++ b/src/Container/ServiceProvider.php @@ -0,0 +1,31 @@ +<?php + +namespace Engelsystem\Container; + +use Engelsystem\Application; + +abstract class ServiceProvider +{ + /** @var Application */ + protected $app; + + /** + * ServiceProvider constructor. + * + * @param Application $app + */ + public function __construct(Application $app) + { + $this->app = $app; + } + + /** + * Register container bindings + */ + public function register() { } + + /** + * Called after other services had been registered + */ + public function boot() { } +} diff --git a/src/Database/DatabaseServiceProvider.php b/src/Database/DatabaseServiceProvider.php new file mode 100644 index 00000000..364816cc --- /dev/null +++ b/src/Database/DatabaseServiceProvider.php @@ -0,0 +1,31 @@ +<?php + +namespace Engelsystem\Database; + +use Engelsystem\Container\ServiceProvider; +use Exception; +use PDO; + +class DatabaseServiceProvider extends ServiceProvider +{ + public function register() + { + $config = $this->app->get('config'); + Db::connect( + 'mysql:host=' . $config->get('database')['host'] . ';dbname=' . $config->get('database')['db'] . ';charset=utf8', + $config->get('database')['user'], + $config->get('database')['pw'] + ) || $this->exitOnError(); + + Db::getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + Db::getPdo()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + } + + /** + * @throws Exception + */ + protected function exitOnError() + { + throw new Exception('Error: Unable to connect to database'); + } +} diff --git a/src/Exceptions/ExceptionsServiceProvider.php b/src/Exceptions/ExceptionsServiceProvider.php new file mode 100644 index 00000000..7755e1e7 --- /dev/null +++ b/src/Exceptions/ExceptionsServiceProvider.php @@ -0,0 +1,15 @@ +<?php + +namespace Engelsystem\Exceptions; + +use Engelsystem\Container\ServiceProvider; +use Engelsystem\Exceptions\Handler as ExceptionHandler; + +class ExceptionsServiceProvider extends ServiceProvider +{ + public function register() + { + $errorHandler = $this->app->make(ExceptionHandler::class); + $this->app->instance('error.handler', $errorHandler); + } +} diff --git a/src/Http/RequestServiceProvider.php b/src/Http/RequestServiceProvider.php new file mode 100644 index 00000000..077e9ecc --- /dev/null +++ b/src/Http/RequestServiceProvider.php @@ -0,0 +1,14 @@ +<?php + +namespace Engelsystem\Http; + +use Engelsystem\Container\ServiceProvider; + +class RequestServiceProvider extends ServiceProvider +{ + public function register() + { + $request = $this->app->call([Request::class, 'createFromGlobals']); + $this->app->instance('request', $request); + } +} diff --git a/src/Http/SessionServiceProvider.php b/src/Http/SessionServiceProvider.php new file mode 100644 index 00000000..55e3f48b --- /dev/null +++ b/src/Http/SessionServiceProvider.php @@ -0,0 +1,52 @@ +<?php + +namespace Engelsystem\Http; + +use Engelsystem\Container\ServiceProvider; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface; + +class SessionServiceProvider extends ServiceProvider +{ + public function register() + { + $sessionStorage = $this->getSessionStorage(); + $this->app->instance('session.storage', $sessionStorage); + $this->app->bind(SessionStorageInterface::class, 'session.storage'); + + $session = $this->app->make(Session::class); + $this->app->instance('session', $session); + + /** @var Request $request */ + $request = $this->app->get('request'); + $request->setSession($session); + + $session->start(); + } + + /** + * Returns the session storage + * + * @return SessionStorageInterface + */ + protected function getSessionStorage() + { + if ($this->isCli()) { + return $this->app->make(MockArraySessionStorage::class); + } + + return $this->app->make(NativeSessionStorage::class, ['options' => ['cookie_httponly' => true]]); + } + + /** + * Test if is called from cli + * + * @return bool + */ + protected function isCli() + { + return PHP_SAPI == 'cli'; + } +} diff --git a/src/Logger/LoggerServiceProvider.php b/src/Logger/LoggerServiceProvider.php new file mode 100644 index 00000000..cf22f383 --- /dev/null +++ b/src/Logger/LoggerServiceProvider.php @@ -0,0 +1,18 @@ +<?php + +namespace Engelsystem\Logger; + +use Engelsystem\Container\ServiceProvider; +use Psr\Log\LoggerInterface; + +class LoggerServiceProvider extends ServiceProvider +{ + public function register() + { + $logger = $this->app->make(EngelsystemLogger::class); + $this->app->instance('logger', $logger); + + $this->app->bind(LoggerInterface::class, 'logger'); + $this->app->bind(EngelsystemLogger::class, 'logger'); + } +} diff --git a/src/Renderer/RendererServiceProvider.php b/src/Renderer/RendererServiceProvider.php new file mode 100644 index 00000000..3e8d69bc --- /dev/null +++ b/src/Renderer/RendererServiceProvider.php @@ -0,0 +1,36 @@ +<?php + +namespace Engelsystem\Renderer; + +use Engelsystem\Container\ServiceProvider; + +class RendererServiceProvider extends ServiceProvider +{ + public function register() + { + $this->registerRenderer(); + $this->registerHtmlEngine(); + } + + public function boot() + { + $renderer = $this->app->get('renderer'); + + foreach ($this->app->tagged('renderer.engine') as $engine) { + $renderer->addRenderer($engine); + } + } + + protected function registerRenderer() + { + $renderer = $this->app->make(Renderer::class); + $this->app->instance('renderer', $renderer); + } + + protected function registerHtmlEngine() + { + $htmlEngine = $this->app->make(HtmlEngine::class); + $this->app->instance('renderer.htmlEngine', $htmlEngine); + $this->app->tag('renderer.htmlEngine', ['renderer.engine']); + } +} diff --git a/src/Routing/RoutingServiceProvider.php b/src/Routing/RoutingServiceProvider.php new file mode 100644 index 00000000..b7db1383 --- /dev/null +++ b/src/Routing/RoutingServiceProvider.php @@ -0,0 +1,14 @@ +<?php + +namespace Engelsystem\Routing; + +use Engelsystem\Container\ServiceProvider; + +class RoutingServiceProvider extends ServiceProvider +{ + public function register() + { + $urlGenerator = $this->app->make(UrlGenerator::class); + $this->app->instance('routing.urlGenerator', $urlGenerator); + } +} diff --git a/src/helpers.php b/src/helpers.php index de303963..5a48498a 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -24,6 +24,15 @@ function app($id = null) } /** + * @param string $path + * @return string + */ +function base_path($path = '') +{ + return app('path') . (empty($path) ? '' : DIRECTORY_SEPARATOR . $path); +} + +/** * Get or set config values * * @param string|array $key @@ -47,6 +56,30 @@ function config($key = null, $default = null) } /** + * @param string $path + * @return string + */ +function config_path($path = '') +{ + return app('path.config') . (empty($path) ? '' : DIRECTORY_SEPARATOR . $path); +} + +/** + * @param string $key + * @param mixed $default + * @return mixed + */ +function env($key, $default = null) +{ + $value = getenv($key); + if ($value === false) { + return $default; + } + + return $value; +} + +/** * @param string $key * @param mixed $default * @return Request|mixed @@ -79,22 +112,6 @@ function session($key = null, $default = null) } /** - * @param string $template - * @param mixed[] $data - * @return Renderer|string - */ -function view($template = null, $data = null) -{ - $renderer = app('renderer'); - - if (is_null($template)) { - return $renderer; - } - - return $renderer->render($template, $data); -} - -/** * @param string $path * @param array $parameters * @return UrlGenerator|string @@ -109,3 +126,19 @@ function url($path = null, $parameters = []) return $urlGenerator->to($path, $parameters); } + +/** + * @param string $template + * @param mixed[] $data + * @return Renderer|string + */ +function view($template = null, $data = null) +{ + $renderer = app('renderer'); + + if (is_null($template)) { + return $renderer; + } + + return $renderer->render($template, $data); +} diff --git a/tests/Feature/Database/DatabaseServiceProviderTest.php b/tests/Feature/Database/DatabaseServiceProviderTest.php new file mode 100644 index 00000000..d5fdd108 --- /dev/null +++ b/tests/Feature/Database/DatabaseServiceProviderTest.php @@ -0,0 +1,40 @@ +<?php + +namespace Engelsystem\Test\Feature\Database; + +use Engelsystem\Application; +use Engelsystem\Config\Config; +use Engelsystem\Database\DatabaseServiceProvider; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +class DatabaseServiceProviderTest extends DatabaseTest +{ + /** + * @covers \Engelsystem\Database\DatabaseServiceProvider::register() + */ + public function testRegister() + { + /** @var MockObject|Config $config */ + $config = $this->getMockBuilder(Config::class) + ->getMock(); + + /** @var MockObject|Application $app */ + $app = $this->getMockBuilder(Application::class) + ->setMethods(['get']) + ->getMock(); + Application::setInstance($app); + + $app->expects($this->once()) + ->method('get') + ->with('config') + ->willReturn($config); + + $config->expects($this->atLeastOnce()) + ->method('get') + ->with('database') + ->willReturn($this->getDbConfig()); + + $serviceProvider = new DatabaseServiceProvider($app); + $serviceProvider->register(); + } +} diff --git a/tests/Feature/Database/DatabaseTest.php b/tests/Feature/Database/DatabaseTest.php new file mode 100644 index 00000000..11df6779 --- /dev/null +++ b/tests/Feature/Database/DatabaseTest.php @@ -0,0 +1,25 @@ +<?php + +namespace Engelsystem\Test\Feature\Database; + +use PHPUnit\Framework\TestCase; + +abstract class DatabaseTest extends TestCase +{ + /** + * Returns the database config + * + * @return string[] + */ + protected function getDbConfig() + { + $configValues = require __DIR__ . '/../../../config/config.default.php'; + $configFile = __DIR__ . '/../../../config/config.php'; + + if (file_exists($configFile)) { + $configValues = array_replace_recursive($configValues, require $configFile); + } + + return $configValues['database']; + } +} diff --git a/tests/Feature/Logger/EngelsystemLoggerTest.php b/tests/Feature/Logger/EngelsystemLoggerTest.php index 63a01318..8886d4ba 100644 --- a/tests/Feature/Logger/EngelsystemLoggerTest.php +++ b/tests/Feature/Logger/EngelsystemLoggerTest.php @@ -1,6 +1,6 @@ <?php -namespace Engelsystem\Test\Logger; +namespace Engelsystem\Test\Feature\Logger; use Engelsystem\Logger\EngelsystemLogger; use PHPUnit\Framework\TestCase; @@ -12,7 +12,7 @@ class EngelsystemLoggerTest extends TestCase { public static function setUpBeforeClass() { - require_once __DIR__ . '/../../../includes/engelsystem_provider.php'; + require_once __DIR__ . '/../../../includes/engelsystem.php'; } /** diff --git a/tests/Feature/model/LogEntriesModelTest.php b/tests/Feature/Model/LogEntriesModelTest.php index 6d7b0ebc..036f5692 100644 --- a/tests/Feature/model/LogEntriesModelTest.php +++ b/tests/Feature/Model/LogEntriesModelTest.php @@ -1,6 +1,6 @@ <?php -namespace Engelsystem\Test; +namespace Engelsystem\Test\Feature\Model; use PHPUnit\Framework\TestCase; use Psr\Log\LogLevel; @@ -9,7 +9,7 @@ class LogEntriesModelTest extends TestCase { public static function setUpBeforeClass() { - require_once __DIR__ . '/../../../includes/engelsystem_provider.php'; + require_once __DIR__ . '/../../../includes/engelsystem.php'; } public function testCreateLogEntry() diff --git a/tests/Feature/model/RoomModelTest.php b/tests/Feature/Model/RoomModelTest.php index 96be84a2..3114ba2d 100644 --- a/tests/Feature/model/RoomModelTest.php +++ b/tests/Feature/Model/RoomModelTest.php @@ -1,6 +1,6 @@ <?php -namespace Engelsystem\Test; +namespace Engelsystem\Test\Feature\Model; use PHPUnit\Framework\TestCase; @@ -10,7 +10,7 @@ class RoomModelTest extends TestCase public static function setUpBeforeClass() { - require_once __DIR__ . '/../../../includes/engelsystem_provider.php'; + require_once __DIR__ . '/../../../includes/engelsystem.php'; } public function create_Room() diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php index 77429f44..f58483ea 100644 --- a/tests/Unit/ApplicationTest.php +++ b/tests/Unit/ApplicationTest.php @@ -1,21 +1,25 @@ <?php -namespace Engelsystem\Test\Config; +namespace Engelsystem\Test\Unit; use Engelsystem\Application; +use Engelsystem\Config\Config; use Engelsystem\Container\Container; +use Engelsystem\Container\ServiceProvider; use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject; use Psr\Container\ContainerInterface; +use ReflectionClass; class ApplicationTest extends TestCase { /** - * @covers \Engelsystem\Application::__construct - * @covers \Engelsystem\Application::registerBaseBindings + * @covers \Engelsystem\Application::__construct + * @covers \Engelsystem\Application::registerBaseBindings */ public function testConstructor() { - $app = new Application(); + $app = new Application('.'); $this->assertInstanceOf(Container::class, $app); $this->assertInstanceOf(ContainerInterface::class, $app); @@ -24,6 +28,144 @@ class ApplicationTest extends TestCase $this->assertSame($app, $app->get(Container::class)); $this->assertSame($app, $app->get(Application::class)); $this->assertSame($app, $app->get(ContainerInterface::class)); + $this->assertSame($app, Application::getInstance()); $this->assertSame($app, Container::getInstance()); } + + /** + * @covers \Engelsystem\Application::setAppPath + * @covers \Engelsystem\Application::registerPaths + * @covers \Engelsystem\Application::path + */ + public function testAppPath() + { + $app = new Application(); + + $this->assertFalse($app->has('path')); + + $app->setAppPath('.'); + $this->assertTrue($app->has('path')); + $this->assertTrue($app->has('path.config')); + $this->assertTrue($app->has('path.lang')); + + $this->assertEquals(realpath('.'), $app->path()); + $this->assertEquals(realpath('.') . '/config', $app->get('path.config')); + + $app->setAppPath('./../'); + $this->assertEquals(realpath('../') . '/config', $app->get('path.config')); + } + + /** + * @covers \Engelsystem\Application::register + */ + public function testRegister() + { + $app = new Application(); + + $serviceProvider = $this->mockServiceProvider($app, ['register']); + $serviceProvider->expects($this->once()) + ->method('register'); + + $app->register($serviceProvider); + + $anotherServiceProvider = $this->mockServiceProvider($app, ['register', 'boot']); + $anotherServiceProvider->expects($this->once()) + ->method('register'); + $anotherServiceProvider->expects($this->once()) + ->method('boot'); + + $app->bootstrap(); + $app->register($anotherServiceProvider); + } + + /** + * @covers \Engelsystem\Application::register + */ + public function testRegisterBoot() + { + $app = new Application(); + $app->bootstrap(); + + $serviceProvider = $this->mockServiceProvider($app, ['register', 'boot']); + $serviceProvider->expects($this->once()) + ->method('register'); + $serviceProvider->expects($this->once()) + ->method('boot'); + + $app->register($serviceProvider); + } + + /** + * @covers \Engelsystem\Application::register + */ + public function testRegisterClassName() + { + $app = new Application(); + + $mockClassName = $this->getMockClass(ServiceProvider::class); + $serviceProvider = $this->getMockBuilder($mockClassName) + ->setConstructorArgs([$app]) + ->setMethods(['register']) + ->getMock(); + + $serviceProvider->expects($this->once()) + ->method('register'); + + $app->instance($mockClassName, $serviceProvider); + $app->register($mockClassName); + } + + /** + * @covers \Engelsystem\Application::bootstrap + * @covers \Engelsystem\Application::isBooted + */ + public function testBootstrap() + { + /** @var PHPUnit_Framework_MockObject_MockObject|Application $app */ + $app = $this->getMockBuilder(Application::class) + ->setMethods(['register']) + ->getMock(); + + $serviceProvider = $this->mockServiceProvider($app, ['boot']); + $serviceProvider->expects($this->once()) + ->method('boot'); + + $app->expects($this->once()) + ->method('register') + ->with($serviceProvider); + + $config = $this->getMockBuilder(Config::class) + ->getMock(); + + $config->expects($this->once()) + ->method('get') + ->with('providers') + ->willReturn([$serviceProvider]); + + $property = (new ReflectionClass($app))->getProperty('serviceProviders'); + $property->setAccessible(true); + $property->setValue($app, [$serviceProvider]); + + $app->bootstrap($config); + + $this->assertTrue($app->isBooted()); + + // Run bootstrap another time to ensure that providers are registered only once + $app->bootstrap($config); + } + + /** + * @param Application $app + * @param array $methods + * @return PHPUnit_Framework_MockObject_MockObject|ServiceProvider + */ + protected function mockServiceProvider(Application $app, $methods = []) + { + $serviceProvider = $this->getMockBuilder(ServiceProvider::class) + ->setConstructorArgs([$app]) + ->setMethods($methods) + ->getMockForAbstractClass(); + + return $serviceProvider; + } } diff --git a/tests/Unit/Config/ConfigServiceProviderTest.php b/tests/Unit/Config/ConfigServiceProviderTest.php new file mode 100644 index 00000000..c8be4b7d --- /dev/null +++ b/tests/Unit/Config/ConfigServiceProviderTest.php @@ -0,0 +1,45 @@ +<?php + +namespace Engelsystem\Test\Unit\Config; + +use Engelsystem\Application; +use Engelsystem\Config\Config; +use Engelsystem\Config\ConfigServiceProvider; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject; + +class ConfigServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Config\ConfigServiceProvider::register() + */ + public function testRegister() + { + /** @var PHPUnit_Framework_MockObject_MockObject|Config $config */ + $config = $this->getMockBuilder(Config::class) + ->getMock(); + + $app = $this->getApp(['make', 'instance', 'get']); + Application::setInstance($app); + + $this->setExpects($app, 'make', [Config::class], $config); + $this->setExpects($app, 'instance', ['config', $config]); + $this->setExpects($app, 'get', ['path.config'], __DIR__ . '/../../../config', $this->atLeastOnce()); + + $this->setExpects($config, 'set', null, null, $this->exactly(2)); + $this->setExpects($config, 'get', [null], []); + + $configFile = __DIR__ . '/../../../config/config.php'; + $configExists = file_exists($configFile); + if (!$configExists) { + file_put_contents($configFile, '<?php return [];'); + } + + $serviceProvider = new ConfigServiceProvider($app); + $serviceProvider->register(); + + if (!$configExists) { + unlink($configFile); + } + } +} diff --git a/tests/Unit/Config/ConfigTest.php b/tests/Unit/Config/ConfigTest.php index ce11ebd6..043599fd 100644 --- a/tests/Unit/Config/ConfigTest.php +++ b/tests/Unit/Config/ConfigTest.php @@ -1,6 +1,6 @@ <?php -namespace Engelsystem\Test\Config; +namespace Engelsystem\Test\Unit\Config; use Engelsystem\Config\Config; use PHPUnit\Framework\TestCase; diff --git a/tests/Unit/Container/ContainerTest.php b/tests/Unit/Container/ContainerTest.php deleted file mode 100644 index 89c34209..00000000 --- a/tests/Unit/Container/ContainerTest.php +++ /dev/null @@ -1,104 +0,0 @@ -<?php - -namespace Engelsystem\Test\Config; - -use Engelsystem\Container\Container; -use PHPUnit\Framework\TestCase; - -class ContainerTest extends TestCase -{ - /** - * @covers \Engelsystem\Container\Container::get - */ - public function testGet() - { - $container = new Container(); - $class = new class - { - }; - - $container->instance('foo', $class); - $this->assertSame($class, $container->get('foo')); - } - - /** - * @covers \Engelsystem\Container\Container::get - * @expectedException \Engelsystem\Container\NotFoundException - */ - public function testGetException() - { - $container = new Container(); - - $container->get('not.registered.service'); - } - - /** - * @covers \Engelsystem\Container\Container::instance - * @covers \Engelsystem\Container\Container::resolve - */ - public function testInstance() - { - $container = new Container(); - $class = new class - { - }; - - $container->instance('foo', $class); - $this->assertSame($class, $container->get('foo')); - } - - /** - * @covers \Engelsystem\Container\Container::has - */ - public function testHas() - { - $container = new Container(); - - $this->assertFalse($container->has('test')); - - $class = new class - { - }; - - $container->instance('test', $class); - $this->assertTrue($container->has('test')); - } - - /** - * @covers \Engelsystem\Container\Container::singleton - */ - public function testSingleton() - { - $container = new Container(); - $class = new class - { - }; - - $container->singleton('foo', $class); - $this->assertSame($class, $container->get('foo')); - $this->assertSame($class, $container->get('foo')); - } - - /** - * @covers \Engelsystem\Container\Container::setInstance - * @covers \Engelsystem\Container\Container::getInstance - */ - public function testContainerSingleton() - { - // Ensure that no container has been initialized - $reflection = new \ReflectionProperty(Container::class, 'instance'); - $reflection->setAccessible(true); - $reflection->setValue(null, null); - $reflection->setAccessible(false); - - $container0 = new Container(); - $container = Container::getInstance(); - - $this->assertNotSame($container0, $container); - - $container1 = new Container; - Container::setInstance($container1); - - $this->assertSame($container1, Container::getInstance()); - } -} diff --git a/tests/Unit/Container/ServiceProviderTest.php b/tests/Unit/Container/ServiceProviderTest.php new file mode 100644 index 00000000..8a9cb76e --- /dev/null +++ b/tests/Unit/Container/ServiceProviderTest.php @@ -0,0 +1,22 @@ +<?php + +namespace Engelsystem\Test\Unit\Container; + +use Engelsystem\Container\ServiceProvider; +use Engelsystem\Test\Unit\Container\Stub\ServiceProviderImplementation; +use Engelsystem\Test\Unit\ServiceProviderTest; + +class ConfigServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Container\ServiceProvider::__construct + */ + public function testRegister() + { + $app = $this->getApp(); + + $serviceProvider = new ServiceProviderImplementation($app); + + $this->assertInstanceOf(ServiceProvider::class, $serviceProvider); + } +} diff --git a/tests/Unit/Container/Stub/ServiceProviderImplementation.php b/tests/Unit/Container/Stub/ServiceProviderImplementation.php new file mode 100644 index 00000000..36ae2c38 --- /dev/null +++ b/tests/Unit/Container/Stub/ServiceProviderImplementation.php @@ -0,0 +1,10 @@ +<?php + +namespace Engelsystem\Test\Unit\Container\Stub; + +use Engelsystem\Container\ServiceProvider; + +class ServiceProviderImplementation extends ServiceProvider +{ + +} diff --git a/tests/Unit/Database/DatabaseServiceProviderTest.php b/tests/Unit/Database/DatabaseServiceProviderTest.php new file mode 100644 index 00000000..61848c35 --- /dev/null +++ b/tests/Unit/Database/DatabaseServiceProviderTest.php @@ -0,0 +1,37 @@ +<?php + +namespace Engelsystem\Test\Unit\Database; + +use Engelsystem\Config\Config; +use Engelsystem\Database\DatabaseServiceProvider; +use Engelsystem\Test\Unit\ServiceProviderTest; +use Exception; +use PHPUnit_Framework_MockObject_MockObject; + +class DatabaseServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Database\DatabaseServiceProvider::register() + * @covers \Engelsystem\Database\DatabaseServiceProvider::exitOnError() + */ + public function testRegister() + { + /** @var PHPUnit_Framework_MockObject_MockObject|Config $config */ + $config = $this->getMockBuilder(Config::class) + ->getMock(); + + $app = $this->getApp(['get']); + + $this->setExpects($app, 'get', ['config'], $config); + $this->setExpects($config, 'get', ['database'], [ + 'host' => 'localhost', + 'db' => 'database', + 'user' => 'user', + 'pw' => 'password', + ], $this->atLeastOnce()); + $this->expectException(Exception::class); + + $serviceProvider = new DatabaseServiceProvider($app); + $serviceProvider->register(); + } +} diff --git a/tests/Unit/Database/DbTest.php b/tests/Unit/Database/DbTest.php new file mode 100644 index 00000000..63607cad --- /dev/null +++ b/tests/Unit/Database/DbTest.php @@ -0,0 +1,192 @@ +<?php + +namespace Engelsystem\Test\Unit\Database; + +use Engelsystem\Database\Db; +use PDO; +use PDOStatement; +use PHPUnit\Framework\TestCase; +use ReflectionObject; +use Throwable; + +class DbTest extends TestCase +{ + /** + * @covers \Engelsystem\Database\Db::connect() + */ + public function testConnect() + { + $result = Db::connect('mysql:host=localhost;dbname=someTestDatabaseThatDoesNotExist;charset=utf8'); + $this->assertFalse($result); + + $result = Db::connect('sqlite::memory:'); + $this->assertTrue($result); + } + + /** + * @covers \Engelsystem\Database\Db::query() + */ + public function testQuery() + { + $stm = Db::query('SELECT * FROM test_data'); + $this->assertEquals('00000', $stm->errorCode()); + + $stm = Db::query('SELECT * FROM test_data WHERE id = ?', [4]); + $this->assertEquals('00000', $stm->errorCode()); + } + + /** + * @covers \Engelsystem\Database\Db::unprepared() + */ + public function testUnprepared() + { + $return = Db::unprepared('SELECT * FROM test_data WHERE id = 3'); + $this->assertTrue($return); + } + + /** + * @covers \Engelsystem\Database\Db::select() + */ + public function testSelect() + { + $return = Db::select('SELECT * FROM test_data'); + $this->assertTrue(count($return) > 3); + + $return = Db::select('SELECT * FROM test_data WHERE id = ?', [2]); + $this->assertCount(1, $return); + } + + /** + * @covers \Engelsystem\Database\Db::selectOne() + */ + public function testSelectOne() + { + $return = Db::selectOne('SELECT * FROM test_data'); + $this->assertEquals('Foo', $return['data']); + + $return = Db::selectOne('SELECT * FROM test_data WHERE id = -1'); + $this->assertEmpty($return); + + $return = Db::selectOne('SELECT * FROM test_data WHERE id = ?', [3]); + $return = array_pop($return); + $this->assertTrue(!is_array($return)); + } + + /** + * @covers \Engelsystem\Database\Db::insert() + */ + public function testInsert() + { + $count = Db::insert("INSERT INTO test_data (id, data) VALUES (5, 'Some random text'), (6, 'another text')"); + $this->assertEquals(2, $count); + + $count = Db::insert('INSERT INTO test_data(id, data) VALUES (:id, :alias)', ['id' => 7, 'alias' => 'Blafoo']); + $this->assertEquals(1, $count); + } + + /** + * @covers \Engelsystem\Database\Db::update() + */ + public function testUpdate() + { + $count = Db::update("UPDATE test_data SET data='NOPE' WHERE data LIKE '%Replaceme%'"); + $this->assertEquals(3, $count); + + $count = Db::update("UPDATE test_data SET data=? WHERE data LIKE '%NOPE%'", ['Some random text!']); + $this->assertEquals(3, $count); + } + + /** + * @covers \Engelsystem\Database\Db::delete() + */ + public function testDelete() + { + $count = Db::delete('DELETE FROM test_data WHERE id=1'); + $this->assertEquals(1, $count); + + $count = Db::delete('DELETE FROM test_data WHERE data LIKE ?', ['%Replaceme%']); + $this->assertEquals(3, $count); + } + + /** + * @covers \Engelsystem\Database\Db::statement() + */ + public function testStatement() + { + $return = Db::statement('SELECT * FROM test_data WHERE id = 3'); + $this->assertTrue($return); + + $return = Db::statement('SELECT * FROM test_data WHERE id = ?', [2]); + $this->assertTrue($return); + } + + /** + * @covers \Engelsystem\Database\Db::getError() + */ + public function testGetError() + { + try { + Db::statement('foo'); + } catch (Throwable $e) { + } + + $error = Db::getError(); + $this->assertTrue(is_array($error)); + $this->assertEquals('near "foo": syntax error', $error[2]); + + $db = new Db(); + $refObject = new ReflectionObject($db); + $refProperty = $refObject->getProperty('stm'); + $refProperty->setAccessible(true); + $refProperty->setValue(null, null); + + $error = Db::getError(); + $this->assertEquals([-1, null, null], $error); + } + + /** + * @covers \Engelsystem\Database\Db::getPdo() + */ + public function testGetPdo() + { + $pdo = Db::getPdo(); + $this->assertInstanceOf(PDO::class, $pdo); + } + + /** + * @covers \Engelsystem\Database\Db::getStm() + */ + public function testGetStm() + { + $stm = Db::getStm(); + $this->assertInstanceOf(PDOStatement::class, $stm); + } + + /** + * Setup in memory database + */ + protected function setUp() + { + Db::connect('sqlite::memory:'); + Db::getPdo()->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + Db::query( + ' + CREATE TABLE test_data( + id INT PRIMARY KEY NOT NULL, + data TEXT NOT NULL + ); + '); + Db::query('CREATE UNIQUE INDEX test_data_id_uindex ON test_data (id);'); + Db::insert(" + INSERT INTO test_data (id, data) + VALUES + (1, 'Foo'), + (2, 'Bar'), + (3, 'Batz'), + (4, 'Lorem ipsum dolor sit'), + (10, 'Replaceme ipsum dolor sit amet'), + (11, 'Lorem Replaceme dolor sit amet'), + (12, 'Lorem ipsum Replaceme sit amet') + ;"); + } +} diff --git a/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php new file mode 100644 index 00000000..9c943d52 --- /dev/null +++ b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php @@ -0,0 +1,29 @@ +<?php + +namespace Engelsystem\Test\Unit\Exceptions; + +use Engelsystem\Exceptions\ExceptionsServiceProvider; +use Engelsystem\Exceptions\Handler as ExceptionHandler; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject; + +class ExceptionsServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::register() + */ + public function testRegister() + { + /** @var PHPUnit_Framework_MockObject_MockObject|ExceptionHandler $exceptionHandler */ + $exceptionHandler = $this->getMockBuilder(ExceptionHandler::class) + ->getMock(); + + $app = $this->getApp(); + + $this->setExpects($app, 'make', [ExceptionHandler::class], $exceptionHandler); + $this->setExpects($app, 'instance', ['error.handler', $exceptionHandler]); + + $serviceProvider = new ExceptionsServiceProvider($app); + $serviceProvider->register(); + } +} diff --git a/tests/Unit/HelpersTest.php b/tests/Unit/HelpersTest.php index d9782888..0a8d5d2b 100644 --- a/tests/Unit/HelpersTest.php +++ b/tests/Unit/HelpersTest.php @@ -1,6 +1,6 @@ <?php -namespace Engelsystem\Test\Config; +namespace Engelsystem\Test\Unit; use Engelsystem\Application; use Engelsystem\Config\Config; @@ -9,6 +9,7 @@ use Engelsystem\Http\Request; use Engelsystem\Renderer\Renderer; use Engelsystem\Routing\UrlGenerator; use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as MockObject; use Symfony\Component\HttpFoundation\Session\Session; class HelpersTest extends TestCase @@ -29,6 +30,25 @@ class HelpersTest extends TestCase } /** + * @covers \base_path() + */ + public function testBasePath() + { + /** @var MockObject|Application $app */ + $app = $this->getMockBuilder(Container::class) + ->getMock(); + Application::setInstance($app); + + $app->expects($this->atLeastOnce()) + ->method('get') + ->with('path') + ->willReturn('/foo/bar'); + + $this->assertEquals('/foo/bar', base_path()); + $this->assertEquals('/foo/bar/bla-foo.conf', base_path('bla-foo.conf')); + } + + /** * @covers \config */ public function testConfig() @@ -54,6 +74,39 @@ class HelpersTest extends TestCase } /** + * @covers \config_path() + */ + public function testConfigPath() + { + /** @var MockObject|Application $app */ + $app = $this->getMockBuilder(Container::class) + ->getMock(); + Application::setInstance($app); + + $app->expects($this->atLeastOnce()) + ->method('get') + ->with('path.config') + ->willReturn('/foo/conf'); + + $this->assertEquals('/foo/conf', config_path()); + $this->assertEquals('/foo/conf/bar.php', config_path('bar.php')); + } + + /** + * @covers \env + */ + public function testEnv() + { + putenv('envTestVar=someContent'); + + $env = env('envTestVar'); + $this->assertEquals('someContent', $env); + + $env = env('someRandomEnvVarThatShouldNeverExist', 'someDefaultValue'); + $this->assertEquals('someDefaultValue', $env); + } + + /** * @covers \request */ public function testRequest() @@ -132,7 +185,7 @@ class HelpersTest extends TestCase /** * @param string $alias * @param object $object - * @return Application|\PHPUnit_Framework_MockObject_MockObject + * @return Application|MockObject */ protected function getAppMock($alias, $object) { diff --git a/tests/Unit/Http/RequestServiceProviderTest.php b/tests/Unit/Http/RequestServiceProviderTest.php new file mode 100644 index 00000000..a137b0ac --- /dev/null +++ b/tests/Unit/Http/RequestServiceProviderTest.php @@ -0,0 +1,29 @@ +<?php + +namespace Engelsystem\Test\Unit\Http; + +use Engelsystem\Http\Request; +use Engelsystem\Http\RequestServiceProvider; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +class RequestServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Http\RequestServiceProvider::register() + */ + public function testRegister() + { + /** @var MockObject|Request $request */ + $request = $this->getMockBuilder(Request::class) + ->getMock(); + + $app = $this->getApp(['call', 'instance']); + + $this->setExpects($app, 'call', [[Request::class, 'createFromGlobals']], $request); + $this->setExpects($app, 'instance', ['request', $request]); + + $serviceProvider = new RequestServiceProvider($app); + $serviceProvider->register(); + } +} diff --git a/tests/Unit/Http/RequestTest.php b/tests/Unit/Http/RequestTest.php new file mode 100644 index 00000000..3f317367 --- /dev/null +++ b/tests/Unit/Http/RequestTest.php @@ -0,0 +1,98 @@ +<?php + +namespace Engelsystem\Test\Unit\Http; + +use Engelsystem\Http\Request; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +class RequestTest extends TestCase +{ + /** + * @covers \Engelsystem\Http\Request::postData + */ + public function testPostData() + { + $request = new Request( + ['foo' => 'I\'m a test!'], + ['foo' => 'bar'] + ); + + $this->assertEquals('bar', $request->postData('foo')); + $this->assertEquals('LoremIpsum', $request->postData('test-key', 'LoremIpsum')); + } + + /** + * @covers \Engelsystem\Http\Request::input + */ + public function testInput() + { + $request = new Request( + ['foo' => 'I\'m a test!'], + ['foo' => 'bar'] + ); + + $this->assertEquals('I\'m a test!', $request->input('foo')); + $this->assertEquals('LoremIpsum', $request->input('test-key', 'LoremIpsum')); + } + + /** + * @covers \Engelsystem\Http\Request::has + */ + public function testHas() + { + $request = new Request([ + 'foo' => 'I\'m a test!', + 'bar' => '', + ]); + + $this->assertTrue($request->has('foo')); + $this->assertFalse($request->has('bar')); + } + + /** + * @covers \Engelsystem\Http\Request::path + */ + public function testPath() + { + /** @var MockObject|Request $request */ + $request = $this + ->getMockBuilder(Request::class) + ->setMethods(['getPathInfo']) + ->getMock(); + + $request + ->expects($this->atLeastOnce()) + ->method('getPathInfo') + ->willReturnOnConsecutiveCalls( + '/foo', + '/' + ); + + $this->assertEquals('foo', $request->path()); + $this->assertEquals('/', $request->path()); + } + + /** + * @covers \Engelsystem\Http\Request::url + */ + public function testUrl() + { + /** @var MockObject|Request $request */ + $request = $this + ->getMockBuilder(Request::class) + ->setMethods(['getUri']) + ->getMock(); + + $request + ->expects($this->atLeastOnce()) + ->method('getUri') + ->willReturnOnConsecutiveCalls( + 'http://foo.bar/bla/foo/', + 'https://lorem.ipsum/dolor/sit?amet=consetetur&sadipscing=elitr' + ); + + $this->assertEquals('http://foo.bar/bla/foo', $request->url()); + $this->assertEquals('https://lorem.ipsum/dolor/sit', $request->url()); + } +} diff --git a/tests/Unit/Http/SessionServiceProviderTest.php b/tests/Unit/Http/SessionServiceProviderTest.php new file mode 100644 index 00000000..0f17a1af --- /dev/null +++ b/tests/Unit/Http/SessionServiceProviderTest.php @@ -0,0 +1,126 @@ +<?php + +namespace Engelsystem\Test\Unit\Http; + +use Engelsystem\Http\Request; +use Engelsystem\Http\SessionServiceProvider; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject as MockObject; +use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; +use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface as StorageInterface; + +class SessionServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Http\SessionServiceProvider::register() + * @covers \Engelsystem\Http\SessionServiceProvider::getSessionStorage() + */ + public function testRegister() + { + $app = $this->getApp(['make', 'instance', 'bind', 'get']); + + $sessionStorage = $this->getMockForAbstractClass(StorageInterface::class); + $sessionStorage2 = $this->getMockForAbstractClass(StorageInterface::class); + + $session = $this->getSessionMock(); + $request = $this->getRequestMock(); + + /** @var MockObject|SessionServiceProvider $serviceProvider */ + $serviceProvider = $this->getMockBuilder(SessionServiceProvider::class) + ->setConstructorArgs([$app]) + ->setMethods(['isCli']) + ->getMock(); + $serviceProvider->expects($this->exactly(2)) + ->method('isCli') + ->willReturnOnConsecutiveCalls(true, false); + + $app->expects($this->exactly(4)) + ->method('make') + ->withConsecutive( + [MockArraySessionStorage::class], + [Session::class], + [NativeSessionStorage::class, ['options' => ['cookie_httponly' => true]]], + [Session::class] + ) + ->willReturnOnConsecutiveCalls( + $sessionStorage, + $session, + $sessionStorage2, + $session + ); + $app->expects($this->atLeastOnce()) + ->method('instance') + ->withConsecutive( + ['session.storage', $sessionStorage], + ['session', $session] + ); + + $this->setExpects($app, 'bind', [StorageInterface::class, 'session.storage'], null, $this->atLeastOnce()); + $this->setExpects($app, 'get', ['request'], $request, $this->atLeastOnce()); + $this->setExpects($request, 'setSession', [$session], null, $this->atLeastOnce()); + $this->setExpects($session, 'start', null, null, $this->atLeastOnce()); + + $serviceProvider->register(); + $serviceProvider->register(); + } + + /** + * @covers \Engelsystem\Http\SessionServiceProvider::isCli() + */ + public function testIsCli() + { + $app = $this->getApp(['make', 'instance', 'bind', 'get']); + + $sessionStorage = $this->getMockForAbstractClass(StorageInterface::class); + + $session = $this->getSessionMock(); + $request = $this->getRequestMock(); + + $app->expects($this->exactly(2)) + ->method('make') + ->withConsecutive( + [MockArraySessionStorage::class], + [Session::class] + ) + ->willReturnOnConsecutiveCalls( + $sessionStorage, + $session + ); + $app->expects($this->exactly(2)) + ->method('instance') + ->withConsecutive( + ['session.storage', $sessionStorage], + ['session', $session] + ); + + $this->setExpects($app, 'bind', [StorageInterface::class, 'session.storage']); + $this->setExpects($app, 'get', ['request'], $request); + $this->setExpects($request, 'setSession', [$session]); + $this->setExpects($session, 'start'); + + $serviceProvider = new SessionServiceProvider($app); + $serviceProvider->register(); + } + + /** + * @return MockObject + */ + private function getSessionMock() + { + return $this->getMockBuilder(Session::class) + ->setMethods(['start']) + ->getMock(); + } + + /** + * @return MockObject + */ + private function getRequestMock() + { + return $this->getMockBuilder(Request::class) + ->setMethods(['setSession']) + ->getMock(); + } +} diff --git a/tests/Unit/Logger/LoggerServiceProviderTest.php b/tests/Unit/Logger/LoggerServiceProviderTest.php new file mode 100644 index 00000000..cef95d5b --- /dev/null +++ b/tests/Unit/Logger/LoggerServiceProviderTest.php @@ -0,0 +1,37 @@ +<?php + +namespace Engelsystem\Test\Unit\Logger; + +use Engelsystem\Logger\EngelsystemLogger; +use Engelsystem\Logger\LoggerServiceProvider; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject; +use Psr\Log\LoggerInterface; + +class LoggerServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Logger\LoggerServiceProvider::register() + */ + public function testRegister() + { + /** @var PHPUnit_Framework_MockObject_MockObject|EngelsystemLogger $logger */ + $logger = $this->getMockBuilder(EngelsystemLogger::class) + ->getMock(); + + $app = $this->getApp(['make', 'instance', 'bind']); + + $this->setExpects($app, 'make', [EngelsystemLogger::class], $logger); + $this->setExpects($app, 'instance', ['logger', $logger]); + + $app->expects($this->atLeastOnce()) + ->method('bind') + ->withConsecutive( + [LoggerInterface::class, 'logger'], + [EngelsystemLogger::class, 'logger'] + ); + + $serviceProvider = new LoggerServiceProvider($app); + $serviceProvider->register(); + } +} diff --git a/tests/Unit/Renderer/HtmlEngineTest.php b/tests/Unit/Renderer/HtmlEngineTest.php index 0b317b72..8c262932 100644 --- a/tests/Unit/Renderer/HtmlEngineTest.php +++ b/tests/Unit/Renderer/HtmlEngineTest.php @@ -1,6 +1,6 @@ <?php -namespace Engelsystem\Test\Config; +namespace Engelsystem\Test\Unit\Renderer; use Engelsystem\Renderer\HtmlEngine; use PHPUnit\Framework\TestCase; diff --git a/tests/Unit/Renderer/RendererServiceProviderTest.php b/tests/Unit/Renderer/RendererServiceProviderTest.php new file mode 100644 index 00000000..3826da7e --- /dev/null +++ b/tests/Unit/Renderer/RendererServiceProviderTest.php @@ -0,0 +1,81 @@ +<?php + +namespace Engelsystem\Test\Unit\Renderer; + +use Engelsystem\Renderer\EngineInterface; +use Engelsystem\Renderer\HtmlEngine; +use Engelsystem\Renderer\Renderer; +use Engelsystem\Renderer\RendererServiceProvider; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject; + +class RendererServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Renderer\RendererServiceProvider::register() + * @covers \Engelsystem\Renderer\RendererServiceProvider::registerRenderer() + * @covers \Engelsystem\Renderer\RendererServiceProvider::registerHtmlEngine() + */ + public function testRegister() + { + /** @var PHPUnit_Framework_MockObject_MockObject|Renderer $renderer */ + $renderer = $this->getMockBuilder(Renderer::class) + ->getMock(); + /** @var PHPUnit_Framework_MockObject_MockObject|HtmlEngine $htmlEngine */ + $htmlEngine = $this->getMockBuilder(HtmlEngine::class) + ->getMock(); + + $app = $this->getApp(['make', 'instance', 'tag']); + + $app->expects($this->exactly(2)) + ->method('make') + ->withConsecutive( + [Renderer::class], + [HtmlEngine::class] + )->willReturnOnConsecutiveCalls( + $renderer, + $htmlEngine + ); + + $app->expects($this->exactly(2)) + ->method('instance') + ->withConsecutive( + ['renderer', $renderer], + ['renderer.htmlEngine', $htmlEngine] + ); + + $this->setExpects($app, 'tag', ['renderer.htmlEngine', ['renderer.engine']]); + + $serviceProvider = new RendererServiceProvider($app); + $serviceProvider->register(); + } + + /** + * @covers \Engelsystem\Renderer\RendererServiceProvider::boot() + */ + public function testBoot() + { + /** @var PHPUnit_Framework_MockObject_MockObject|Renderer $renderer */ + $renderer = $this->getMockBuilder(Renderer::class) + ->getMock(); + /** @var PHPUnit_Framework_MockObject_MockObject|EngineInterface $engine1 */ + $engine1 = $this->getMockForAbstractClass(EngineInterface::class); + /** @var PHPUnit_Framework_MockObject_MockObject|EngineInterface $engine2 */ + $engine2 = $this->getMockForAbstractClass(EngineInterface::class); + + $app = $this->getApp(['get', 'tagged']); + + $engines = [$engine1, $engine2]; + + $this->setExpects($app, 'get', ['renderer'], $renderer); + $this->setExpects($app, 'tagged', ['renderer.engine'], $engines); + + $invocation = $renderer + ->expects($this->exactly(count($engines))) + ->method('addRenderer'); + call_user_func_array([$invocation, 'withConsecutive'], $engines); + + $serviceProvider = new RendererServiceProvider($app); + $serviceProvider->boot(); + } +} diff --git a/tests/Unit/Renderer/RendererTest.php b/tests/Unit/Renderer/RendererTest.php index b0238078..969ced7f 100644 --- a/tests/Unit/Renderer/RendererTest.php +++ b/tests/Unit/Renderer/RendererTest.php @@ -1,10 +1,11 @@ <?php -namespace Engelsystem\Test\Config; +namespace Engelsystem\Test\Unit\Renderer; use Engelsystem\Renderer\EngineInterface; use Engelsystem\Renderer\Renderer; use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as MockObject; use Psr\Log\LoggerInterface; class RendererTest extends TestCase @@ -13,6 +14,7 @@ class RendererTest extends TestCase { $renderer = new Renderer(); + /** @var MockObject|EngineInterface $nullRenderer */ $nullRenderer = $this->getMockForAbstractClass(EngineInterface::class); $nullRenderer->expects($this->atLeastOnce()) @@ -20,6 +22,7 @@ class RendererTest extends TestCase ->willReturn(false); $renderer->addRenderer($nullRenderer); + /** @var MockObject|EngineInterface $mockRenderer */ $mockRenderer = $this->getMockForAbstractClass(EngineInterface::class); $mockRenderer->expects($this->atLeastOnce()) @@ -42,6 +45,7 @@ class RendererTest extends TestCase { $renderer = new Renderer(); + /** @var MockObject|LoggerInterface $loggerMock */ $loggerMock = $this->getMockForAbstractClass(LoggerInterface::class); $loggerMock ->expects($this->once()) diff --git a/tests/Unit/Routing/RoutingServiceProviderTest.php b/tests/Unit/Routing/RoutingServiceProviderTest.php new file mode 100644 index 00000000..dd9441eb --- /dev/null +++ b/tests/Unit/Routing/RoutingServiceProviderTest.php @@ -0,0 +1,29 @@ +<?php + +namespace Engelsystem\Test\Unit\Routing; + +use Engelsystem\Routing\RoutingServiceProvider; +use Engelsystem\Routing\UrlGenerator; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject; + +class RoutingServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Routing\RoutingServiceProvider::register() + */ + public function testRegister() + { + /** @var PHPUnit_Framework_MockObject_MockObject|UrlGenerator $urlGenerator */ + $urlGenerator = $this->getMockBuilder(UrlGenerator::class) + ->getMock(); + + $app = $this->getApp(); + + $this->setExpects($app, 'make', [UrlGenerator::class], $urlGenerator); + $this->setExpects($app, 'instance', ['routing.urlGenerator', $urlGenerator]); + + $serviceProvider = new RoutingServiceProvider($app); + $serviceProvider->register(); + } +} diff --git a/tests/Unit/Routing/UrlGeneratorTest.php b/tests/Unit/Routing/UrlGeneratorTest.php index fc23520a..6da59a4f 100644 --- a/tests/Unit/Routing/UrlGeneratorTest.php +++ b/tests/Unit/Routing/UrlGeneratorTest.php @@ -1,6 +1,6 @@ <?php -namespace Engelsystem\Test\Config; +namespace Engelsystem\Test\Unit\Routing; use Engelsystem\Application; use Engelsystem\Container\Container; diff --git a/tests/Unit/ServiceProviderTest.php b/tests/Unit/ServiceProviderTest.php new file mode 100644 index 00000000..dc58a65e --- /dev/null +++ b/tests/Unit/ServiceProviderTest.php @@ -0,0 +1,50 @@ +<?php + +namespace Engelsystem\Test\Unit; + +use Engelsystem\Application; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_Matcher_InvokedRecorder as InvokedRecorder; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +abstract class ServiceProviderTest extends TestCase +{ + /** + * @param array $methods + * @return Application|MockObject + */ + protected function getApp($methods = ['make', 'instance']) + { + /** @var MockObject|Application $app */ + return $this->getMockBuilder(Application::class) + ->setMethods($methods) + ->getMock(); + } + + /** + * @param MockObject $object + * @param string $method + * @param array $arguments + * @param mixed $return + * @param InvokedRecorder $times + */ + protected function setExpects($object, $method, $arguments = null, $return = null, $times = null) + { + if (is_null($times)) { + $times = $this->once(); + } + + $invocation = $object->expects($times) + ->method($method); + + if (is_null($arguments)) { + $invocation->withAnyParameters(); + } else { + call_user_func_array([$invocation, 'with'], $arguments); + } + + if (!is_null($return)) { + $invocation->willReturn($return); + } + } +} diff --git a/tests/autoload.php b/tests/autoload.php new file mode 100644 index 00000000..3168ce3d --- /dev/null +++ b/tests/autoload.php @@ -0,0 +1,8 @@ +<?php + +use Composer\Autoload\ClassLoader; + +require_once __DIR__ . '/../includes/autoload.php'; + +/** @var $loader ClassLoader */ +$loader->addPsr4('Engelsystem\\Test\\', __DIR__ . '/'); |