From c57dfc631caf98df46ac014812f962863f0bfa61 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 19 Sep 2017 19:50:59 +0200 Subject: engelsystem_provider should not be loaded in phpunit, changed dir structure --- tests/Feature/Logger/EngelsystemLoggerTest.php | 136 +++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/Feature/Logger/EngelsystemLoggerTest.php (limited to 'tests/Feature/Logger/EngelsystemLoggerTest.php') diff --git a/tests/Feature/Logger/EngelsystemLoggerTest.php b/tests/Feature/Logger/EngelsystemLoggerTest.php new file mode 100644 index 00000000..3b6572f5 --- /dev/null +++ b/tests/Feature/Logger/EngelsystemLoggerTest.php @@ -0,0 +1,136 @@ +assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); + } + + /** + * @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); + } + + /** + * @return string[] + */ + public function provideLogLevels() + { + return [ + [LogLevel::ALERT], + [LogLevel::CRITICAL], + [LogLevel::DEBUG], + [LogLevel::EMERGENCY], + [LogLevel::ERROR], + [LogLevel::INFO], + [LogLevel::NOTICE], + [LogLevel::WARNING], + ]; + } + + 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']); + + foreach ( + [ + ['Data and {context}', []], + ['Data and ', ['context' => null]], + ['Data and {context}', ['context' => new \stdClass()]], + ] as $data + ) { + list($result, $context) = $data; + + $logger->log(LogLevel::INFO, 'Data and {context}', $context); + + $entry = $this->getLastEntry(); + $this->assertEquals($result, $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(); + } +} -- cgit v1.2.3-54-g00ecf From c35c4ccbf39a5910530d6cf9b4f5dba45dbf82b0 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 19 Sep 2017 20:40:48 +0200 Subject: Refactoring: Logger test cleanup --- tests/Feature/Logger/EngelsystemLoggerTest.php | 72 +++++++++++++++----------- 1 file changed, 43 insertions(+), 29 deletions(-) (limited to 'tests/Feature/Logger/EngelsystemLoggerTest.php') diff --git a/tests/Feature/Logger/EngelsystemLoggerTest.php b/tests/Feature/Logger/EngelsystemLoggerTest.php index 3b6572f5..63a01318 100644 --- a/tests/Feature/Logger/EngelsystemLoggerTest.php +++ b/tests/Feature/Logger/EngelsystemLoggerTest.php @@ -28,23 +28,6 @@ class EngelsystemLoggerTest extends TestCase $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger()); } - /** - * @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); - } - /** * @return string[] */ @@ -62,6 +45,23 @@ class EngelsystemLoggerTest extends TestCase ]; } + /** + * @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(); @@ -72,21 +72,35 @@ class EngelsystemLoggerTest extends TestCase $entry = $this->getLastEntry(); $this->assertEquals('My username is Foo', $entry['message']); $this->assertEquals(LogLevel::INFO, $entry['level']); + } - foreach ( - [ - ['Data and {context}', []], - ['Data and ', ['context' => null]], - ['Data and {context}', ['context' => new \stdClass()]], - ] as $data - ) { - list($result, $context) = $data; + /** + * @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?'], + ]; + } - $logger->log(LogLevel::INFO, 'Data and {context}', $context); + /** + * @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($result, $entry['message']); - } + $entry = $this->getLastEntry(); + $this->assertEquals($expected, $entry['message']); } public function testContextToString() -- cgit v1.2.3-54-g00ecf From e15e86362585f5d00d118653232584ed0920e533 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 31 Oct 2017 14:23:23 +0100 Subject: Added tests for base_path and config_path --- .../DatabaseServiceProviderConnectionTest.php | 2 +- tests/Feature/Logger/EngelsystemLoggerTest.php | 2 +- tests/Feature/Model/LogEntriesModelTest.php | 38 +++++++++++++++++++ tests/Feature/Model/RoomModelTest.php | 40 ++++++++++++++++++++ tests/Feature/model/LogEntriesModelTest.php | 38 ------------------- tests/Feature/model/RoomModelTest.php | 40 -------------------- tests/Unit/ApplicationTest.php | 2 +- tests/Unit/Config/ConfigServiceProviderTest.php | 2 +- tests/Unit/Config/ConfigTest.php | 2 +- .../Unit/Database/DatabaseServiceProviderTest.php | 2 +- .../Exceptions/ExceptionsServiceProviderTest.php | 2 +- tests/Unit/HelpersTest.php | 43 +++++++++++++++++++++- tests/Unit/Logger/LoggerServiceProviderTest.php | 2 +- tests/Unit/Renderer/HtmlEngineTest.php | 2 +- .../Unit/Renderer/RendererServiceProviderTest.php | 2 +- tests/Unit/Renderer/RendererTest.php | 6 ++- tests/Unit/Routing/RoutingServiceProviderTest.php | 2 +- tests/Unit/Routing/UrlGeneratorTest.php | 2 +- 18 files changed, 136 insertions(+), 93 deletions(-) create mode 100644 tests/Feature/Model/LogEntriesModelTest.php create mode 100644 tests/Feature/Model/RoomModelTest.php delete mode 100644 tests/Feature/model/LogEntriesModelTest.php delete mode 100644 tests/Feature/model/RoomModelTest.php (limited to 'tests/Feature/Logger/EngelsystemLoggerTest.php') diff --git a/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php b/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php index dd1ce729..636fba2e 100644 --- a/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php +++ b/tests/Feature/Database/DatabaseServiceProviderConnectionTest.php @@ -1,6 +1,6 @@ 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..20b9e34d --- /dev/null +++ b/tests/Feature/Model/RoomModelTest.php @@ -0,0 +1,40 @@ +room_id = Room_create('test', false, true, ''); + } + + public function test_Room() + { + $this->create_Room(); + + $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/Feature/model/LogEntriesModelTest.php b/tests/Feature/model/LogEntriesModelTest.php deleted file mode 100644 index 6d7b0ebc..00000000 --- a/tests/Feature/model/LogEntriesModelTest.php +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 96be84a2..00000000 --- a/tests/Feature/model/RoomModelTest.php +++ /dev/null @@ -1,40 +0,0 @@ -room_id = Room_create('test', false, true, ''); - } - - public function test_Room() - { - $this->create_Room(); - - $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 index 78310134..f58483ea 100644 --- a/tests/Unit/ApplicationTest.php +++ b/tests/Unit/ApplicationTest.php @@ -1,6 +1,6 @@ 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 */ @@ -53,6 +73,25 @@ class HelpersTest extends TestCase $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 */ @@ -146,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/Logger/LoggerServiceProviderTest.php b/tests/Unit/Logger/LoggerServiceProviderTest.php index 66f63cf4..cef95d5b 100644 --- a/tests/Unit/Logger/LoggerServiceProviderTest.php +++ b/tests/Unit/Logger/LoggerServiceProviderTest.php @@ -1,6 +1,6 @@ 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 index bb2a1d65..dd9441eb 100644 --- a/tests/Unit/Routing/RoutingServiceProviderTest.php +++ b/tests/Unit/Routing/RoutingServiceProviderTest.php @@ -1,6 +1,6 @@ Date: Wed, 1 Nov 2017 12:35:45 +0100 Subject: Moved includes to own file --- includes/engelsystem.php | 77 ++++++++++++ includes/engelsystem_provider.php | 156 ------------------------- includes/includes.php | 86 ++++++++++++++ public/index.php | 6 +- tests/Feature/Logger/EngelsystemLoggerTest.php | 2 +- tests/Feature/Model/LogEntriesModelTest.php | 2 +- tests/Feature/Model/RoomModelTest.php | 2 +- 7 files changed, 171 insertions(+), 160 deletions(-) create mode 100644 includes/engelsystem.php delete mode 100644 includes/engelsystem_provider.php create mode 100644 includes/includes.php (limited to 'tests/Feature/Logger/EngelsystemLoggerTest.php') diff --git a/includes/engelsystem.php b/includes/engelsystem.php new file mode 100644 index 00000000..f9535847 --- /dev/null +++ b/includes/engelsystem.php @@ -0,0 +1,77 @@ +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(); +} + + +/** + * Initialize Request + * + * @var Request $request + */ +$request = Request::createFromGlobals(); +$app->instance('request', $request); + + +/** + * Include legacy code + */ +require __DIR__ . '/includes.php'; + + +/** + * 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/engelsystem_provider.php b/includes/engelsystem_provider.php deleted file mode 100644 index 48206cb6..00000000 --- a/includes/engelsystem_provider.php +++ /dev/null @@ -1,156 +0,0 @@ -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(); -} - - -/** - * Initialize Request - * - * @var Request $request - */ -$request = Request::createFromGlobals(); -$app->instance('request', $request); - - -/** - * Include legacy code - */ -$includeFiles = [ - __DIR__ . '/../includes/sys_auth.php', - __DIR__ . '/../includes/sys_form.php', - __DIR__ . '/../includes/sys_log.php', - __DIR__ . '/../includes/sys_menu.php', - __DIR__ . '/../includes/sys_page.php', - __DIR__ . '/../includes/sys_template.php', - - __DIR__ . '/../includes/model/AngelType_model.php', - __DIR__ . '/../includes/model/EventConfig_model.php', - __DIR__ . '/../includes/model/LogEntries_model.php', - __DIR__ . '/../includes/model/Message_model.php', - __DIR__ . '/../includes/model/NeededAngelTypes_model.php', - __DIR__ . '/../includes/model/Room_model.php', - __DIR__ . '/../includes/model/ShiftEntry_model.php', - __DIR__ . '/../includes/model/Shifts_model.php', - __DIR__ . '/../includes/model/ShiftsFilter.php', - __DIR__ . '/../includes/model/ShiftSignupState.php', - __DIR__ . '/../includes/model/ShiftTypes_model.php', - __DIR__ . '/../includes/model/UserAngelTypes_model.php', - __DIR__ . '/../includes/model/UserDriverLicenses_model.php', - __DIR__ . '/../includes/model/UserGroups_model.php', - __DIR__ . '/../includes/model/User_model.php', - __DIR__ . '/../includes/model/ValidationResult.php', - - __DIR__ . '/../includes/view/AngelTypes_view.php', - __DIR__ . '/../includes/view/EventConfig_view.php', - __DIR__ . '/../includes/view/Questions_view.php', - __DIR__ . '/../includes/view/Rooms_view.php', - __DIR__ . '/../includes/view/ShiftCalendarLane.php', - __DIR__ . '/../includes/view/ShiftCalendarRenderer.php', - __DIR__ . '/../includes/view/ShiftCalendarShiftRenderer.php', - __DIR__ . '/../includes/view/ShiftsFilterRenderer.php', - __DIR__ . '/../includes/view/Shifts_view.php', - __DIR__ . '/../includes/view/ShiftEntry_view.php', - __DIR__ . '/../includes/view/ShiftTypes_view.php', - __DIR__ . '/../includes/view/UserAngelTypes_view.php', - __DIR__ . '/../includes/view/UserDriverLicenses_view.php', - __DIR__ . '/../includes/view/UserHintsRenderer.php', - __DIR__ . '/../includes/view/User_view.php', - - __DIR__ . '/../includes/controller/angeltypes_controller.php', - __DIR__ . '/../includes/controller/event_config_controller.php', - __DIR__ . '/../includes/controller/rooms_controller.php', - __DIR__ . '/../includes/controller/shift_entries_controller.php', - __DIR__ . '/../includes/controller/shifts_controller.php', - __DIR__ . '/../includes/controller/shifttypes_controller.php', - __DIR__ . '/../includes/controller/users_controller.php', - __DIR__ . '/../includes/controller/user_angeltypes_controller.php', - __DIR__ . '/../includes/controller/user_driver_licenses_controller.php', - - __DIR__ . '/../includes/helper/graph_helper.php', - __DIR__ . '/../includes/helper/internationalization_helper.php', - __DIR__ . '/../includes/helper/message_helper.php', - __DIR__ . '/../includes/helper/error_helper.php', - __DIR__ . '/../includes/helper/email_helper.php', - - __DIR__ . '/../includes/mailer/shifts_mailer.php', - __DIR__ . '/../includes/mailer/users_mailer.php', - - __DIR__ . '/../includes/pages/admin_active.php', - __DIR__ . '/../includes/pages/admin_arrive.php', - __DIR__ . '/../includes/pages/admin_free.php', - __DIR__ . '/../includes/pages/admin_groups.php', - __DIR__ . '/../includes/pages/admin_import.php', - __DIR__ . '/../includes/pages/admin_log.php', - __DIR__ . '/../includes/pages/admin_questions.php', - __DIR__ . '/../includes/pages/admin_rooms.php', - __DIR__ . '/../includes/pages/admin_shifts.php', - __DIR__ . '/../includes/pages/admin_user.php', - __DIR__ . '/../includes/pages/guest_login.php', - __DIR__ . '/../includes/pages/user_messages.php', - __DIR__ . '/../includes/pages/user_myshifts.php', - __DIR__ . '/../includes/pages/user_news.php', - __DIR__ . '/../includes/pages/user_questions.php', - __DIR__ . '/../includes/pages/user_settings.php', - __DIR__ . '/../includes/pages/user_shifts.php', -]; -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/includes.php b/includes/includes.php new file mode 100644 index 00000000..a42f960f --- /dev/null +++ b/includes/includes.php @@ -0,0 +1,86 @@ +get('request'); $page = $request->query->get('p'); if (empty($page)) { $page = $request->path(); diff --git a/tests/Feature/Logger/EngelsystemLoggerTest.php b/tests/Feature/Logger/EngelsystemLoggerTest.php index 9f502198..8886d4ba 100644 --- a/tests/Feature/Logger/EngelsystemLoggerTest.php +++ b/tests/Feature/Logger/EngelsystemLoggerTest.php @@ -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 2678dcb5..036f5692 100644 --- a/tests/Feature/Model/LogEntriesModelTest.php +++ b/tests/Feature/Model/LogEntriesModelTest.php @@ -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 20b9e34d..3114ba2d 100644 --- a/tests/Feature/Model/RoomModelTest.php +++ b/tests/Feature/Model/RoomModelTest.php @@ -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() -- cgit v1.2.3-54-g00ecf