summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormsquare <msquare@notrademark.de>2017-11-12 13:25:56 +0100
committerGitHub <noreply@github.com>2017-11-12 13:25:56 +0100
commitebc973bf221bfbde327868975221e62704e4cb99 (patch)
tree9011a160f3d6f9cae37fc02836e7d6e8c25242ca
parent801c17aa6cef91be988a25a90442be8d2078a70d (diff)
parentad948bdd3201e922b626a736b0122533bdd37cae (diff)
Merge pull request #349 from MyIgel/master
Changed container to Illuminate/Container and added service providers
-rw-r--r--.gitlab-ci.yml90
-rw-r--r--composer.json9
-rw-r--r--config/app.php17
-rw-r--r--config/config.default.php8
-rw-r--r--db/install.sql4
-rw-r--r--includes/autoload.php2
-rw-r--r--includes/engelsystem.php61
-rw-r--r--includes/helper/internationalization_helper.php2
-rw-r--r--includes/includes.php (renamed from includes/engelsystem_provider.php)124
-rw-r--r--includes/model/Shifts_model.php4
-rw-r--r--includes/model/UserAngelTypes_model.php2
-rw-r--r--includes/pages/user_shifts.php2
-rw-r--r--phpunit.xml3
-rw-r--r--public/index.php6
-rw-r--r--src/Application.php118
-rw-r--r--src/Config/ConfigServiceProvider.php26
-rw-r--r--src/Container/Container.php110
-rw-r--r--src/Container/ContainerException.php11
-rw-r--r--src/Container/NotFoundException.php10
-rw-r--r--src/Container/ServiceProvider.php31
-rw-r--r--src/Database/DatabaseServiceProvider.php31
-rw-r--r--src/Exceptions/ExceptionsServiceProvider.php15
-rw-r--r--src/Http/RequestServiceProvider.php14
-rw-r--r--src/Http/SessionServiceProvider.php52
-rw-r--r--src/Logger/LoggerServiceProvider.php18
-rw-r--r--src/Renderer/RendererServiceProvider.php36
-rw-r--r--src/Routing/RoutingServiceProvider.php14
-rw-r--r--src/helpers.php65
-rw-r--r--tests/Feature/Database/DatabaseServiceProviderTest.php40
-rw-r--r--tests/Feature/Database/DatabaseTest.php25
-rw-r--r--tests/Feature/Logger/EngelsystemLoggerTest.php4
-rw-r--r--tests/Feature/Model/LogEntriesModelTest.php (renamed from tests/Feature/model/LogEntriesModelTest.php)4
-rw-r--r--tests/Feature/Model/RoomModelTest.php (renamed from tests/Feature/model/RoomModelTest.php)4
-rw-r--r--tests/Unit/ApplicationTest.php150
-rw-r--r--tests/Unit/Config/ConfigServiceProviderTest.php45
-rw-r--r--tests/Unit/Config/ConfigTest.php2
-rw-r--r--tests/Unit/Container/ContainerTest.php104
-rw-r--r--tests/Unit/Container/ServiceProviderTest.php22
-rw-r--r--tests/Unit/Container/Stub/ServiceProviderImplementation.php10
-rw-r--r--tests/Unit/Database/DatabaseServiceProviderTest.php37
-rw-r--r--tests/Unit/Database/DbTest.php192
-rw-r--r--tests/Unit/Exceptions/ExceptionsServiceProviderTest.php29
-rw-r--r--tests/Unit/HelpersTest.php57
-rw-r--r--tests/Unit/Http/RequestServiceProviderTest.php29
-rw-r--r--tests/Unit/Http/RequestTest.php98
-rw-r--r--tests/Unit/Http/SessionServiceProviderTest.php126
-rw-r--r--tests/Unit/Logger/LoggerServiceProviderTest.php37
-rw-r--r--tests/Unit/Renderer/HtmlEngineTest.php2
-rw-r--r--tests/Unit/Renderer/RendererServiceProviderTest.php81
-rw-r--r--tests/Unit/Renderer/RendererTest.php6
-rw-r--r--tests/Unit/Routing/RoutingServiceProviderTest.php29
-rw-r--r--tests/Unit/Routing/UrlGeneratorTest.php2
-rw-r--r--tests/Unit/ServiceProviderTest.php50
-rw-r--r--tests/autoload.php8
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__ . '/');