diff options
author | msquare <msquare@notrademark.de> | 2017-11-28 15:43:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-28 15:43:51 +0100 |
commit | 599f2fd264bfc7b1b6826fe206442806e317340f (patch) | |
tree | 50cf84d7d07d11bd65b45c2c17f37632f6cd8eff /tests | |
parent | a5fc5bd0979e8de1fce8a8addd351a6e7bd6aeb8 (diff) | |
parent | eda7f7788ea8012bd8be46405c56a666c11f3fa5 (diff) |
Merge pull request #365 from engelsystem/feature-igel-rewrite
Feature igel rewrite
Diffstat (limited to 'tests')
29 files changed, 2153 insertions, 0 deletions
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 new file mode 100644 index 00000000..8886d4ba --- /dev/null +++ b/tests/Feature/Logger/EngelsystemLoggerTest.php @@ -0,0 +1,150 @@ +<?php + +namespace Engelsystem\Test\Feature\Logger; + +use Engelsystem\Logger\EngelsystemLogger; +use PHPUnit\Framework\TestCase; +use Psr\Log\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; + +class EngelsystemLoggerTest extends TestCase +{ + public static function setUpBeforeClass() + { + require_once __DIR__ . '/../../../includes/engelsystem.php'; + } + + /** + * @return LoggerInterface + */ + public function getLogger() + { + return new EngelsystemLogger(); + } + + public function testImplements() + { + $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @return string[] + */ + public function provideLogLevels() + { + return [ + [LogLevel::ALERT], + [LogLevel::CRITICAL], + [LogLevel::DEBUG], + [LogLevel::EMERGENCY], + [LogLevel::ERROR], + [LogLevel::INFO], + [LogLevel::NOTICE], + [LogLevel::WARNING], + ]; + } + + /** + * @dataProvider provideLogLevels + * @param string $level + */ + public function testAllLevels($level) + { + $logger = $this->getLogger(); + + LogEntries_clear_all(); + + $logger->log($level, 'First log message'); + $logger->{$level}('Second log message'); + + $entries = LogEntries(); + $this->assertCount(2, $entries); + } + + public function testContextReplacement() + { + $logger = $this->getLogger(); + LogEntries_clear_all(); + + $logger->log(LogLevel::INFO, 'My username is {username}', ['username' => 'Foo']); + + $entry = $this->getLastEntry(); + $this->assertEquals('My username is Foo', $entry['message']); + $this->assertEquals(LogLevel::INFO, $entry['level']); + } + + /** + * @return string[] + */ + public function provideContextReplaceValues() + { + return [ + ['Data and {context}', [], 'Data and {context}'], + ['Data and {context}', ['context' => null], 'Data and '], + ['Data and {context}', ['context' => new \stdClass()], 'Data and {context}'], + ['Some user asked: {question}', ['question' => 'Foo?'], 'Some user asked: Foo?'], + ]; + } + + /** + * @dataProvider provideContextReplaceValues + * + * @param string $message + * @param string[] $context + * @param string $expected + */ + public function testContextReplaceValues($message, $context, $expected) + { + $logger = $this->getLogger(); + $logger->log(LogLevel::INFO, $message, $context); + + $entry = $this->getLastEntry(); + $this->assertEquals($expected, $entry['message']); + } + + public function testContextToString() + { + $logger = $this->getLogger(); + LogEntries_clear_all(); + + $mock = $this->getMockBuilder('someDataProvider') + ->setMethods(['__toString']) + ->getMock(); + + $mock->expects($this->atLeastOnce()) + ->method('__toString') + ->will($this->returnValue('FooBar')); + + $logger->log(LogLevel::INFO, 'Some data and {context}', ['context' => $mock]); + + $entry = $this->getLastEntry(); + $this->assertEquals('Some data and FooBar', $entry['message']); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testThrowExceptionOnInvalidLevel() + { + $logger = $this->getLogger(); + + $logger->log('This log level should never be defined', 'Some message'); + } + + /** + * @return array + */ + public function getLastEntry() + { + $entries = LogEntries(); + $entry = array_pop($entries); + + return $entry; + } + + public function tearDown() + { + LogEntries_clear_all(); + } +} diff --git a/tests/Feature/Model/LogEntriesModelTest.php b/tests/Feature/Model/LogEntriesModelTest.php new file mode 100644 index 00000000..036f5692 --- /dev/null +++ b/tests/Feature/Model/LogEntriesModelTest.php @@ -0,0 +1,38 @@ +<?php + +namespace Engelsystem\Test\Feature\Model; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LogLevel; + +class LogEntriesModelTest extends TestCase +{ + public static function setUpBeforeClass() + { + require_once __DIR__ . '/../../../includes/engelsystem.php'; + } + + public function testCreateLogEntry() + { + LogEntries_clear_all(); + $count = count(LogEntries()); + $this->assertNotFalse(LogEntry_create(LogLevel::WARNING, 'test_LogEntry_create')); + + // There should be one more log entry now + $this->assertEquals(count(LogEntries()), $count + 1); + } + + public function testClearAllLogEntries() + { + LogEntry_create(LogLevel::WARNING, 'test'); + $this->assertTrue(count(LogEntries()) > 0); + + $this->assertNotFalse(LogEntries_clear_all()); + $this->assertCount(0, LogEntries()); + } + + public function tearDown() + { + LogEntries_clear_all(); + } +} diff --git a/tests/Feature/Model/RoomModelTest.php b/tests/Feature/Model/RoomModelTest.php new file mode 100644 index 00000000..adf0218e --- /dev/null +++ b/tests/Feature/Model/RoomModelTest.php @@ -0,0 +1,40 @@ +<?php + +namespace Engelsystem\Test\Feature\Model; + +use PHPUnit\Framework\TestCase; + +class RoomModelTest extends TestCase +{ + private $room_id = null; + + public static function setUpBeforeClass() + { + require_once __DIR__ . '/../../../includes/engelsystem.php'; + } + + public function createRoom() + { + $this->room_id = Room_create('test', false, true, ''); + } + + public function testRoom() + { + $this->createRoom(); + + $room = Room($this->room_id); + + $this->assertNotFalse($room); + $this->assertNotNull($room); + $this->assertEquals($room['Name'], 'test'); + + $this->assertNull(Room(-1)); + } + + public function tearDown() + { + if ($this->room_id != null) { + Room_delete($this->room_id); + } + } +} diff --git a/tests/Unit/ApplicationTest.php b/tests/Unit/ApplicationTest.php new file mode 100644 index 00000000..f58483ea --- /dev/null +++ b/tests/Unit/ApplicationTest.php @@ -0,0 +1,171 @@ +<?php + +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 + */ + public function testConstructor() + { + $app = new Application('.'); + + $this->assertInstanceOf(Container::class, $app); + $this->assertInstanceOf(ContainerInterface::class, $app); + $this->assertSame($app, $app->get('app')); + $this->assertSame($app, $app->get('container')); + $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 new file mode 100644 index 00000000..043599fd --- /dev/null +++ b/tests/Unit/Config/ConfigTest.php @@ -0,0 +1,115 @@ +<?php + +namespace Engelsystem\Test\Unit\Config; + +use Engelsystem\Config\Config; +use PHPUnit\Framework\TestCase; + +class ConfigTest extends TestCase +{ + /** + * @covers \Engelsystem\Config\Config::get + */ + public function testGet() + { + $config = new Config(); + + $config->set('test', 'FooBar'); + $this->assertEquals(['test' => 'FooBar'], $config->get(null)); + $this->assertEquals('FooBar', $config->get('test')); + + $this->assertEquals('defaultValue', $config->get('notExisting', 'defaultValue')); + + $this->assertNull($config->get('notExisting')); + } + + /** + * @covers \Engelsystem\Config\Config::set + */ + public function testSet() + { + $config = new Config(); + + $config->set('test', 'FooBar'); + $this->assertEquals('FooBar', $config->get('test')); + + $config->set([ + 'name' => 'Engelsystem', + 'mail' => ['user' => 'test'], + ]); + $this->assertEquals('Engelsystem', $config->get('name')); + $this->assertEquals(['user' => 'test'], $config->get('mail')); + } + + /** + * @covers \Engelsystem\Config\Config::has + */ + public function testHas() + { + $config = new Config(); + + $this->assertFalse($config->has('test')); + + $config->set('test', 'FooBar'); + $this->assertTrue($config->has('test')); + } + + /** + * @covers \Engelsystem\Config\Config::remove + */ + public function testRemove() + { + $config = new Config(); + $config->set(['foo' => 'bar', 'test' => '123']); + + $config->remove('foo'); + $this->assertEquals(['test' => '123'], $config->get(null)); + } + + /** + * @covers \Engelsystem\Config\Config::__get + */ + public function testMagicGet() + { + $config = new Config(); + + $config->set('test', 'FooBar'); + $this->assertEquals('FooBar', $config->test); + } + + /** + * @covers \Engelsystem\Config\Config::__set + */ + public function testMagicSet() + { + $config = new Config(); + + $config->test = 'FooBar'; + $this->assertEquals('FooBar', $config->get('test')); + } + + /** + * @covers \Engelsystem\Config\Config::__isset + */ + public function testMagicIsset() + { + $config = new Config(); + + $this->assertFalse(isset($config->test)); + + $config->set('test', 'FooBar'); + $this->assertTrue(isset($config->test)); + } + + /** + * @covers \Engelsystem\Config\Config::__unset + */ + public function testMagicUnset() + { + $config = new Config(); + $config->set(['foo' => 'bar', 'test' => '123']); + + unset($config->foo); + $this->assertEquals(['test' => '123'], $config->get(null)); + } +} 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..4f2ae654 --- /dev/null +++ b/tests/Unit/Exceptions/ExceptionsServiceProviderTest.php @@ -0,0 +1,109 @@ +<?php + +namespace Engelsystem\Test\Unit\Exceptions; + +use Engelsystem\Exceptions\ExceptionsServiceProvider; +use Engelsystem\Exceptions\Handler; +use Engelsystem\Exceptions\Handlers\HandlerInterface; +use Engelsystem\Exceptions\Handlers\Legacy; +use Engelsystem\Exceptions\Handlers\LegacyDevelopment; +use Engelsystem\Exceptions\Handlers\Whoops; +use Engelsystem\Http\Request; +use Engelsystem\Test\Unit\ServiceProviderTest; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +class ExceptionsServiceProviderTest extends ServiceProviderTest +{ + /** + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::register() + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::addProductionHandler() + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::addDevelopmentHandler() + */ + public function testRegister() + { + $app = $this->getApp(['make', 'instance', 'bind']); + + /** @var MockObject|Handler $handler */ + $handler = $this->createMock(Handler::class); + $this->setExpects($handler, 'register'); + /** @var Legacy|MockObject $legacyHandler */ + $legacyHandler = $this->createMock(Legacy::class); + /** @var LegacyDevelopment|MockObject $developmentHandler */ + $developmentHandler = $this->createMock(LegacyDevelopment::class); + + $whoopsHandler = $this->getMockBuilder(Whoops::class) + ->setConstructorArgs([$app]) + ->getMock(); + + $app->expects($this->exactly(3)) + ->method('instance') + ->withConsecutive( + ['error.handler.production', $legacyHandler], + ['error.handler.development', $whoopsHandler], + ['error.handler', $handler] + ); + + $app->expects($this->exactly(4)) + ->method('make') + ->withConsecutive( + [Handler::class], + [Legacy::class], + [LegacyDevelopment::class], + [Whoops::class] + ) + ->willReturnOnConsecutiveCalls( + $handler, + $legacyHandler, + $developmentHandler, + $whoopsHandler + ); + + $app->expects($this->exactly(2)) + ->method('bind') + ->withConsecutive( + [HandlerInterface::class, 'error.handler.production'], + [Handler::class, 'error.handler'] + ); + + $handler->expects($this->exactly(2)) + ->method('setHandler') + ->withConsecutive( + [Handler::ENV_PRODUCTION, $legacyHandler], + [Handler::ENV_DEVELOPMENT, $whoopsHandler] + ); + + $serviceProvider = new ExceptionsServiceProvider($app); + $serviceProvider->register(); + } + + /** + * @covers \Engelsystem\Exceptions\ExceptionsServiceProvider::boot() + */ + public function testBoot() + { + /** @var MockObject|Handler $handler */ + $handler = $this->createMock(Handler::class); + + /** @var MockObject|Request $request */ + $request = $this->createMock(Request::class); + + $handler->expects($this->once()) + ->method('setRequest') + ->with($request); + + $app = $this->getApp(['get']); + $app->expects($this->exactly(2)) + ->method('get') + ->withConsecutive( + ['error.handler'], + ['request'] + ) + ->willReturnOnConsecutiveCalls( + $handler, + $request + ); + + $provider = new ExceptionsServiceProvider($app); + $provider->boot(); + } +} diff --git a/tests/Unit/Exceptions/HandlerTest.php b/tests/Unit/Exceptions/HandlerTest.php new file mode 100644 index 00000000..40202be8 --- /dev/null +++ b/tests/Unit/Exceptions/HandlerTest.php @@ -0,0 +1,140 @@ +<?php + +namespace Engelsystem\Test\Unit\Exceptions; + +use Engelsystem\Exceptions\Handler; +use Engelsystem\Exceptions\Handlers\HandlerInterface; +use Engelsystem\Http\Request; +use ErrorException; +use Exception; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as Mock; + +class HandlerTest extends TestCase +{ + /** + * @covers \Engelsystem\Exceptions\Handler::__construct() + */ + public function testCreate() + { + /** @var Handler|Mock $handler */ + $handler = new Handler(); + $this->assertInstanceOf(Handler::class, $handler); + $this->assertEquals(Handler::ENV_PRODUCTION, $handler->getEnvironment()); + + $anotherHandler = new Handler(Handler::ENV_DEVELOPMENT); + $this->assertEquals(Handler::ENV_DEVELOPMENT, $anotherHandler->getEnvironment()); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::errorHandler() + */ + public function testErrorHandler() + { + /** @var Handler|Mock $handler */ + $handler = $this->getMockBuilder(Handler::class) + ->setMethods(['exceptionHandler']) + ->getMock(); + + $handler->expects($this->once()) + ->method('exceptionHandler') + ->with($this->isInstanceOf(ErrorException::class)); + + $handler->errorHandler(1, 'Foo and bar!', '/lo/rem.php', 123); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::exceptionHandler() + */ + public function testExceptionHandler() + { + $exception = new Exception(); + + /** @var HandlerInterface|Mock $handlerMock */ + $handlerMock = $this->getMockForAbstractClass(HandlerInterface::class); + $handlerMock->expects($this->once()) + ->method('report') + ->with($exception); + $handlerMock->expects($this->once()) + ->method('render') + ->with($this->isInstanceOf(Request::class), $exception); + + /** @var Handler|Mock $handler */ + $handler = $this->getMockBuilder(Handler::class) + ->setMethods(['die']) + ->getMock(); + $handler->expects($this->once()) + ->method('die'); + + $handler->setHandler(Handler::ENV_PRODUCTION, $handlerMock); + + $handler->exceptionHandler($exception); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::register() + */ + public function testRegister() + { + /** @var Handler|Mock $handler */ + $handler = $this->getMockForAbstractClass(Handler::class); + $handler->register(); + + set_error_handler($errorHandler = set_error_handler('var_dump')); + $this->assertEquals($handler, array_shift($errorHandler)); + + set_exception_handler($exceptionHandler = set_error_handler('var_dump')); + $this->assertEquals($handler, array_shift($exceptionHandler)); + + restore_error_handler(); + restore_exception_handler(); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::setEnvironment() + * @covers \Engelsystem\Exceptions\Handler::getEnvironment() + */ + public function testEnvironment() + { + $handler = new Handler(); + + $handler->setEnvironment(Handler::ENV_DEVELOPMENT); + $this->assertEquals(Handler::ENV_DEVELOPMENT, $handler->getEnvironment()); + + $handler->setEnvironment(Handler::ENV_PRODUCTION); + $this->assertEquals(Handler::ENV_PRODUCTION, $handler->getEnvironment()); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::setHandler() + * @covers \Engelsystem\Exceptions\Handler::getHandler() + */ + public function testHandler() + { + $handler = new Handler(); + /** @var HandlerInterface|Mock $devHandler */ + $devHandler = $this->getMockForAbstractClass(HandlerInterface::class); + /** @var HandlerInterface|Mock $prodHandler */ + $prodHandler = $this->getMockForAbstractClass(HandlerInterface::class); + + $handler->setHandler(Handler::ENV_DEVELOPMENT, $devHandler); + $handler->setHandler(Handler::ENV_PRODUCTION, $prodHandler); + $this->assertEquals($devHandler, $handler->getHandler(Handler::ENV_DEVELOPMENT)); + $this->assertEquals($prodHandler, $handler->getHandler(Handler::ENV_PRODUCTION)); + $this->assertCount(2, $handler->getHandler()); + } + + /** + * @covers \Engelsystem\Exceptions\Handler::setRequest() + * @covers \Engelsystem\Exceptions\Handler::getRequest() + */ + public function testRequest() + { + $handler = new Handler(); + /** @var Request|Mock $request */ + $request = $this->createMock(Request::class); + + $handler->setRequest($request); + $this->assertEquals($request, $handler->getRequest()); + } +} diff --git a/tests/Unit/Exceptions/Handlers/LegacyDevelopmentTest.php b/tests/Unit/Exceptions/Handlers/LegacyDevelopmentTest.php new file mode 100644 index 00000000..d5390c9e --- /dev/null +++ b/tests/Unit/Exceptions/Handlers/LegacyDevelopmentTest.php @@ -0,0 +1,35 @@ +<?php + +namespace Engelsystem\Test\Unit\Exceptions\handlers; + + +use Engelsystem\Exceptions\Handlers\LegacyDevelopment; +use Engelsystem\Http\Request; +use ErrorException; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as Mock; + +class LegacyDevelopmentTest extends TestCase +{ + /** + * @covers \Engelsystem\Exceptions\Handlers\LegacyDevelopment::render() + * @covers \Engelsystem\Exceptions\Handlers\LegacyDevelopment::formatStackTrace() + */ + public function testRender() + { + $handler = new LegacyDevelopment(); + /** @var Request|Mock $request */ + $request = $this->createMock(Request::class); + $exception = new ErrorException('Lorem Ipsum', 4242, 1, 'foo.php', 9999); + + $regex = sprintf( + '%%<pre.*>.*ErrorException.*4242.*Lorem Ipsum.*%s.*%s.*%s.*</pre>%%is', + 'foo.php', + 9999, + __FUNCTION__ + ); + $this->expectOutputRegex($regex); + + $handler->render($request, $exception); + } +} diff --git a/tests/Unit/Exceptions/Handlers/LegacyTest.php b/tests/Unit/Exceptions/Handlers/LegacyTest.php new file mode 100644 index 00000000..04b214f2 --- /dev/null +++ b/tests/Unit/Exceptions/Handlers/LegacyTest.php @@ -0,0 +1,55 @@ +<?php + +namespace Engelsystem\Test\Unit\Exceptions\handlers; + + +use Engelsystem\Exceptions\Handlers\Legacy; +use Engelsystem\Http\Request; +use Exception; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as Mock; + +class LegacyTest extends TestCase +{ + /** + * @covers \Engelsystem\Exceptions\Handlers\Legacy::render() + */ + public function testRender() + { + $handler = new Legacy(); + /** @var Request|Mock $request */ + $request = $this->createMock(Request::class); + /** @var Exception|Mock $exception */ + $exception = $this->createMock(Exception::class); + + $this->expectOutputRegex('/.*error occurred.*/i'); + + $handler->render($request, $exception); + } + + /** + * @covers \Engelsystem\Exceptions\Handlers\Legacy::report() + * @covers \Engelsystem\Exceptions\Handlers\Legacy::stripBasePath() + */ + public function testReport() + { + $handler = new Legacy(); + $exception = new Exception('Lorem Ipsum', 4242); + $line = __LINE__ - 1; + + $log = tempnam(sys_get_temp_dir(), 'engelsystem-log'); + $errorLog = ini_get('error_log'); + ini_set('error_log', $log); + $handler->report($exception); + ini_set('error_log', $errorLog); + $logContent = file_get_contents($log); + unset($log); + + $this->assertContains('4242', $logContent); + $this->assertContains('Lorem Ipsum', $logContent); + $this->assertContains(basename(__FILE__), $logContent); + $this->assertContains((string)$line, $logContent); + $this->assertContains(__FUNCTION__, $logContent); + $this->assertContains(json_encode(__CLASS__), $logContent); + } +} diff --git a/tests/Unit/Exceptions/Handlers/WhoopsTest.php b/tests/Unit/Exceptions/Handlers/WhoopsTest.php new file mode 100644 index 00000000..261ee83f --- /dev/null +++ b/tests/Unit/Exceptions/Handlers/WhoopsTest.php @@ -0,0 +1,83 @@ +<?php + +namespace Engelsystem\Test\Unit\Exceptions\handlers; + + +use Engelsystem\Application; +use Engelsystem\Exceptions\Handlers\Whoops; +use Engelsystem\Http\Request; +use Exception; +use PHPUnit\Framework\TestCase; +use PHPUnit_Framework_MockObject_MockObject as Mock; +use Whoops\Handler\JsonResponseHandler; +use Whoops\Handler\PrettyPageHandler; +use Whoops\Run as WhoopsRunner; +use Whoops\RunInterface as WhoopsRunnerInterface; + +class WhoopsTest extends TestCase +{ + /** + * @covers \Engelsystem\Exceptions\Handlers\Whoops + */ + public function testRender() + { + /** @var Application|Mock $app */ + $app = $this->createMock(Application::class); + /** @var Request|Mock $request */ + $request = $this->createMock(Request::class); + $request->expects($this->once()) + ->method('isXmlHttpRequest') + ->willReturn(true); + /** @var WhoopsRunnerInterface|Mock $whoopsRunner */ + $whoopsRunner = $this->getMockForAbstractClass(WhoopsRunnerInterface::class); + /** @var PrettyPageHandler|Mock $prettyPageHandler */ + $prettyPageHandler = $this->createMock(PrettyPageHandler::class); + $prettyPageHandler + ->expects($this->atLeastOnce()) + ->method('setApplicationPaths'); + $prettyPageHandler + ->expects($this->once()) + ->method('setApplicationPaths'); + $prettyPageHandler + ->expects($this->once()) + ->method('addDataTable'); + /** @var JsonResponseHandler|Mock $jsonResponseHandler */ + $jsonResponseHandler = $this->createMock(JsonResponseHandler::class); + $jsonResponseHandler->expects($this->once()) + ->method('setJsonApi') + ->with(true); + $jsonResponseHandler->expects($this->once()) + ->method('addTraceToOutput') + ->with(true); + /** @var Exception|Mock $exception */ + $exception = $this->createMock(Exception::class); + + $app->expects($this->exactly(3)) + ->method('make') + ->withConsecutive( + [WhoopsRunner::class], + [PrettyPageHandler::class], + [JsonResponseHandler::class] + ) + ->willReturnOnConsecutiveCalls( + $whoopsRunner, + $prettyPageHandler, + $jsonResponseHandler + ); + + $whoopsRunner + ->expects($this->exactly(2)) + ->method('pushHandler') + ->withConsecutive( + [$prettyPageHandler], + [$jsonResponseHandler] + ); + $whoopsRunner + ->expects($this->once()) + ->method('handleException') + ->with($exception); + + $handler = new Whoops($app); + $handler->render($request, $exception); + } +} diff --git a/tests/Unit/HelpersTest.php b/tests/Unit/HelpersTest.php new file mode 100644 index 00000000..43c29c84 --- /dev/null +++ b/tests/Unit/HelpersTest.php @@ -0,0 +1,208 @@ +<?php + +namespace Engelsystem\Test\Unit; + +use Engelsystem\Application; +use Engelsystem\Config\Config; +use Engelsystem\Container\Container; +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; +use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface as StorageInterface; + +class HelpersTest extends TestCase +{ + /** + * @covers \app + */ + public function testApp() + { + $class = new class + { + }; + + $appMock = $this->getAppMock('some.name', $class); + + $this->assertEquals($appMock, app()); + $this->assertEquals($class, app('some.name')); + } + + /** + * @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() + { + $configMock = $this->getMockBuilder(Config::class) + ->getMock(); + + $this->getAppMock('config', $configMock); + $this->assertEquals($configMock, config()); + + $configMock->expects($this->once()) + ->method('set') + ->with(['foo' => 'bar']); + + $this->assertTrue(config(['foo' => 'bar'])); + + $configMock->expects($this->once()) + ->method('get') + ->with('mail') + ->willReturn(['user' => 'FooBar']); + + $this->assertEquals(['user' => 'FooBar'], config('mail')); + } + + /** + * @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() + { + $requestMock = $this->getMockBuilder(Request::class) + ->getMock(); + + $this->getAppMock('request', $requestMock); + $this->assertEquals($requestMock, request()); + + $requestMock->expects($this->once()) + ->method('input') + ->with('requestKey') + ->willReturn('requestValue'); + + $this->assertEquals('requestValue', request('requestKey')); + } + + /** + * @covers \session + */ + public function testSession() + { + $sessionStorage = $this->getMockForAbstractClass(StorageInterface::class); + $sessionMock = $this->getMockBuilder(Session::class) + ->setConstructorArgs([$sessionStorage]) + ->getMock(); + + $this->getAppMock('session', $sessionMock); + $this->assertEquals($sessionMock, session()); + + $sessionMock->expects($this->once()) + ->method('get') + ->with('someKey') + ->willReturn('someValue'); + + $this->assertEquals('someValue', session('someKey')); + } + + /** + * @covers \view + */ + public function testView() + { + $rendererMock = $this->getMockBuilder(Renderer::class) + ->getMock(); + + $this->getAppMock('renderer', $rendererMock); + $this->assertEquals($rendererMock, view()); + + $rendererMock->expects($this->once()) + ->method('render') + ->with('template.name', ['template' => 'data']) + ->willReturn('rendered template'); + + $this->assertEquals('rendered template', view('template.name', ['template' => 'data'])); + } + + /** + * @covers \url + */ + public function testUrl() + { + $urlGeneratorMock = $this->getMockBuilder(UrlGenerator::class) + ->getMock(); + + $this->getAppMock('routing.urlGenerator', $urlGeneratorMock); + $this->assertEquals($urlGeneratorMock, url()); + + $urlGeneratorMock->expects($this->once()) + ->method('to') + ->with('foo/bar', ['param' => 'value']) + ->willReturn('http://lorem.ipsum/foo/bar?param=value'); + + $this->assertEquals('http://lorem.ipsum/foo/bar?param=value', url('foo/bar', ['param' => 'value'])); + } + + /** + * @param string $alias + * @param object $object + * @return Application|MockObject + */ + protected function getAppMock($alias, $object) + { + $appMock = $this->getMockBuilder(Container::class) + ->getMock(); + + $appMock->expects($this->atLeastOnce()) + ->method('get') + ->with($alias) + ->willReturn($object); + + /** @var $appMock Application */ + Application::setInstance($appMock); + + return $appMock; + } +} 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..a68f8b8f --- /dev/null +++ b/tests/Unit/Http/RequestTest.php @@ -0,0 +1,99 @@ +<?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->assertTrue($request->has('bar')); + $this->assertFalse($request->has('baz')); + } + + /** + * @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..a78b4f72 --- /dev/null +++ b/tests/Unit/Http/SessionServiceProviderTest.php @@ -0,0 +1,128 @@ +<?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() + { + $sessionStorage = $this->getMockForAbstractClass(StorageInterface::class); + return $this->getMockBuilder(Session::class) + ->setConstructorArgs([$sessionStorage]) + ->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 new file mode 100644 index 00000000..8c262932 --- /dev/null +++ b/tests/Unit/Renderer/HtmlEngineTest.php @@ -0,0 +1,67 @@ +<?php + +namespace Engelsystem\Test\Unit\Renderer; + +use Engelsystem\Renderer\HtmlEngine; +use PHPUnit\Framework\TestCase; + +class HtmlEngineTest extends TestCase +{ + /** @var string[] */ + protected $tmpFileNames = []; + + /** + * @covers \Engelsystem\Renderer\HtmlEngine::get + */ + public function testGet() + { + $engine = new HtmlEngine(); + + $file = $this->createTempFile('<div>%main_content%</div>'); + + $data = $engine->get($file, ['main_content' => 'Lorem ipsum dolor sit']); + $this->assertEquals('<div>Lorem ipsum dolor sit</div>', $data); + } + + /** + * @covers \Engelsystem\Renderer\HtmlEngine::canRender + */ + public function testCanRender() + { + $engine = new HtmlEngine(); + + $this->assertFalse($engine->canRender('/dev/null')); + + $file = $this->createTempFile(); + $this->assertTrue($engine->canRender($file)); + + $htmFile = $this->createTempFile('', '.htm'); + $this->assertTrue($engine->canRender($htmFile)); + } + + /** + * @param string $content + * @param string $extension + * @return string + */ + protected function createTempFile($content = '', $extension = '.html') + { + $tmpFileName = tempnam(sys_get_temp_dir(), 'EngelsystemUnitTest'); + + $fileName = $tmpFileName . $extension; + rename($tmpFileName, $fileName); + + file_put_contents($fileName, $content); + + $this->tmpFileNames[] = $fileName; + + return $fileName; + } + + public function tearDown() + { + foreach ($this->tmpFileNames as $fileName) { + unlink($fileName); + } + } +} 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 new file mode 100644 index 00000000..969ced7f --- /dev/null +++ b/tests/Unit/Renderer/RendererTest.php @@ -0,0 +1,59 @@ +<?php + +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 +{ + public function testGet() + { + $renderer = new Renderer(); + + /** @var MockObject|EngineInterface $nullRenderer */ + $nullRenderer = $this->getMockForAbstractClass(EngineInterface::class); + + $nullRenderer->expects($this->atLeastOnce()) + ->method('canRender') + ->willReturn(false); + $renderer->addRenderer($nullRenderer); + + /** @var MockObject|EngineInterface $mockRenderer */ + $mockRenderer = $this->getMockForAbstractClass(EngineInterface::class); + + $mockRenderer->expects($this->atLeastOnce()) + ->method('canRender') + ->with('foo.template') + ->willReturn(true); + + $mockRenderer->expects($this->atLeastOnce()) + ->method('get') + ->with('foo.template', ['lorem' => 'ipsum']) + ->willReturn('Rendered content'); + + $renderer->addRenderer($mockRenderer); + $data = $renderer->render('foo.template', ['lorem' => 'ipsum']); + + $this->assertEquals('Rendered content', $data); + } + + public function testError() + { + $renderer = new Renderer(); + + /** @var MockObject|LoggerInterface $loggerMock */ + $loggerMock = $this->getMockForAbstractClass(LoggerInterface::class); + $loggerMock + ->expects($this->once()) + ->method('error'); + + $renderer->setLogger($loggerMock); + + $data = $renderer->render('testing.template'); + $this->assertEquals('', $data); + } +} 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 new file mode 100644 index 00000000..6da59a4f --- /dev/null +++ b/tests/Unit/Routing/UrlGeneratorTest.php @@ -0,0 +1,51 @@ +<?php + +namespace Engelsystem\Test\Unit\Routing; + +use Engelsystem\Application; +use Engelsystem\Container\Container; +use Engelsystem\Http\Request; +use Engelsystem\Routing\UrlGenerator; +use PHPUnit\Framework\TestCase; + +class UrlGeneratorTest extends TestCase +{ + public function provideLinksTo() + { + return [ + ['/foo/path', '/foo/path', 'http://foo.bar/foo/path', [], 'http://foo.bar/foo/path'], + ['foo', '/foo', 'https://foo.bar/foo', [], 'https://foo.bar/foo'], + ['foo', '/foo', 'http://f.b/foo', ['test' => 'abc', 'bla' => 'foo'], 'http://f.b/foo?test=abc&bla=foo'], + ]; + } + + /** + * @dataProvider provideLinksTo + * @covers \Engelsystem\Routing\UrlGenerator::to + * + * @param string $path + * @param string $willReturn + * @param string $urlToPath + * @param string[] $arguments + * @param string $expectedUrl + */ + public function testTo($urlToPath, $path, $willReturn, $arguments, $expectedUrl) + { + $app = new Container(); + $urlGenerator = new UrlGenerator(); + Application::setInstance($app); + + $request = $this->getMockBuilder(Request::class) + ->getMock(); + + $request->expects($this->once()) + ->method('getUriForPath') + ->with($path) + ->willReturn($willReturn); + + $app->instance('request', $request); + + $url = $urlGenerator->to($urlToPath, $arguments); + $this->assertEquals($expectedUrl, $url); + } +} 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__ . '/'); |