From 2899ebb5b5e82890c877151f5c02045266ac9973 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Fri, 22 May 2020 13:20:31 +0200 Subject: Initialize admin Slim controllers - Reorganize visitor controllers - Fix redirection with Slim's requests base path - Fix daily links --- .../controller/visitor/DailyControllerTest.php | 497 +++++++++++++++++++++ .../controller/visitor/FeedControllerTest.php | 151 +++++++ .../visitor/FrontControllerMockHelper.php | 114 +++++ .../controller/visitor/LoginControllerTest.php | 144 ++++++ .../visitor/OpenSearchControllerTest.php | 46 ++ .../visitor/PictureWallControllerTest.php | 125 ++++++ .../visitor/ShaarliPublicControllerTest.php | 239 ++++++++++ .../controller/visitor/TagCloudControllerTest.php | 381 ++++++++++++++++ .../front/controller/visitor/TagControllerTest.php | 241 ++++++++++ 9 files changed, 1938 insertions(+) create mode 100644 tests/front/controller/visitor/DailyControllerTest.php create mode 100644 tests/front/controller/visitor/FeedControllerTest.php create mode 100644 tests/front/controller/visitor/FrontControllerMockHelper.php create mode 100644 tests/front/controller/visitor/LoginControllerTest.php create mode 100644 tests/front/controller/visitor/OpenSearchControllerTest.php create mode 100644 tests/front/controller/visitor/PictureWallControllerTest.php create mode 100644 tests/front/controller/visitor/ShaarliPublicControllerTest.php create mode 100644 tests/front/controller/visitor/TagCloudControllerTest.php create mode 100644 tests/front/controller/visitor/TagControllerTest.php (limited to 'tests/front/controller/visitor') diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php new file mode 100644 index 00000000..6ff769fc --- /dev/null +++ b/tests/front/controller/visitor/DailyControllerTest.php @@ -0,0 +1,497 @@ +createContainer(); + + $this->controller = new DailyController($this->container); + DailyController::$DAILY_RSS_NB_DAYS = 2; + } + + public function testValidIndexControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $request->method('getQueryParam')->willReturn($currentDay->format('Ymd')); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + '20200510', + $currentDay->format('Ymd'), + '20200516', + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark()) + ->setId(1) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + (new Bookmark()) + ->setId(2) + ->setUrl('http://url2.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + (new Bookmark()) + ->setId(3) + ->setUrl('http://url3.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { + static::assertSame('render_daily', $hook); + + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(3, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame($currentDay->getTimestamp(), $data['day']); + static::assertSame('20200510', $data['previousday']); + static::assertSame('20200516', $data['nextday']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertSame( + 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', + $assignedVariables['pagetitle'] + ); + static::assertEquals($currentDay, $assignedVariables['dayDate']); + static::assertEquals($currentDay->getTimestamp(), $assignedVariables['day']); + static::assertCount(3, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['linksToDisplay'][1]; + + static::assertSame(2, $link['id']); + static::assertSame('http://url2.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['linksToDisplay'][2]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + static::assertCount(3, $assignedVariables['cols']); + static::assertCount(1, $assignedVariables['cols'][0]); + static::assertCount(1, $assignedVariables['cols'][1]); + static::assertCount(1, $assignedVariables['cols'][2]); + + $link = $assignedVariables['cols'][0][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['cols'][1][0]; + + static::assertSame(2, $link['id']); + static::assertSame('http://url2.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + + $link = $assignedVariables['cols'][2][0]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertNotEmpty($link['title']); + static::assertNotEmpty($link['description']); + static::assertNotEmpty($link['formatedDescription']); + } + + /** + * Daily page - test that everything goes fine with no future or past bookmarks + */ + public function testValidIndexControllerInvokeNoFutureOrPast(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + $currentDay->format($currentDay->format('Ymd')), + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark()) + ->setId(1) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(500)) + , + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { + static::assertSame('render_daily', $hook); + + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(1, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame($currentDay->getTimestamp(), $data['day']); + static::assertEmpty($data['previousday']); + static::assertEmpty($data['nextday']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertSame( + 'Daily - '. format_date($currentDay, false, true) .' - Shaarli', + $assignedVariables['pagetitle'] + ); + static::assertCount(1, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + static::assertSame(1, $link['id']); + } + + /** + * Daily page - test that height adjustment in columns is working + */ + public function testValidIndexControllerInvokeHeightAdjustment(): void + { + $this->createValidContainerMockSet(); + + $currentDay = new \DateTimeImmutable('2020-05-13'); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function () use ($currentDay): array { + return [ + $currentDay->format($currentDay->format('Ymd')), + ]; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return [ + (new Bookmark())->setId(1)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark()) + ->setId(2) + ->setUrl('http://url.tld') + ->setTitle(static::generateContent(50)) + ->setDescription(static::generateContent(5000)) + , + (new Bookmark())->setId(3)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(4)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(5)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(6)->setUrl('http://url.tld')->setTitle('title'), + (new Bookmark())->setId(7)->setUrl('http://url.tld')->setTitle('title'), + ]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertCount(7, $assignedVariables['linksToDisplay']); + + $columnIds = function (array $column): array { + return array_map(function (array $item): int { return $item['id']; }, $column); + }; + + static::assertSame([1, 4, 6], $columnIds($assignedVariables['cols'][0])); + static::assertSame([2], $columnIds($assignedVariables['cols'][1])); + static::assertSame([3, 5, 7], $columnIds($assignedVariables['cols'][2])); + } + + /** + * Daily page - no bookmark + */ + public function testValidIndexControllerInvokeNoBookmark(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('days') + ->willReturnCallback(function (): array { + return []; + }) + ; + $this->container->bookmarkService + ->expects(static::once()) + ->method('filterDay') + ->willReturnCallback(function (): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + return $data; + }) + ; + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('daily', (string) $result->getBody()); + static::assertCount(0, $assignedVariables['linksToDisplay']); + static::assertSame('Today', $assignedVariables['dayDesc']); + static::assertEquals((new \DateTime())->setTime(0, 0)->getTimestamp(), $assignedVariables['day']); + static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']); + } + + /** + * Daily RSS - default behaviour + */ + public function testValidRssControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $dates = [ + new \DateTimeImmutable('2020-05-17'), + new \DateTimeImmutable('2020-05-15'), + new \DateTimeImmutable('2020-05-13'), + ]; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([ + (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), + (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), + (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), + (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'), + ]); + + $this->container->pageCacheManager + ->expects(static::once()) + ->method('getCachePage') + ->willReturnCallback(function (): CachedPage { + $cachedPage = $this->createMock(CachedPage::class); + $cachedPage->expects(static::once())->method('cache')->with('dailyrss'); + + return $cachedPage; + } + ); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('dailyrss', (string) $result->getBody()); + static::assertSame('Shaarli', $assignedVariables['title']); + static::assertSame('http://shaarli', $assignedVariables['index_url']); + static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); + static::assertFalse($assignedVariables['hide_timestamps']); + static::assertCount(2, $assignedVariables['days']); + + $day = $assignedVariables['days'][$dates[0]->format('Ymd')]; + + static::assertEquals($dates[0], $day['date']); + static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']); + static::assertSame(format_date($dates[0], false), $day['date_human']); + static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']); + static::assertCount(1, $day['links']); + static::assertSame(1, $day['links'][0]['id']); + static::assertSame('http://domain.tld/1', $day['links'][0]['url']); + static::assertEquals($dates[0], $day['links'][0]['created']); + + $day = $assignedVariables['days'][$dates[1]->format('Ymd')]; + + static::assertEquals($dates[1], $day['date']); + static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']); + static::assertSame(format_date($dates[1], false), $day['date_human']); + static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']); + static::assertCount(2, $day['links']); + + static::assertSame(2, $day['links'][0]['id']); + static::assertSame('http://domain.tld/2', $day['links'][0]['url']); + static::assertEquals($dates[1], $day['links'][0]['created']); + static::assertSame(3, $day['links'][1]['id']); + static::assertSame('http://domain.tld/3', $day['links'][1]['url']); + static::assertEquals($dates[1], $day['links'][1]['created']); + } + + /** + * Daily RSS - trigger cache rendering + */ + public function testValidRssControllerInvokeTriggerCache(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->pageCacheManager->method('getCachePage')->willReturnCallback(function (): CachedPage { + $cachedPage = $this->createMock(CachedPage::class); + $cachedPage->method('cachedVersion')->willReturn('this is cache!'); + + return $cachedPage; + }); + + $this->container->bookmarkService->expects(static::never())->method('search'); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('this is cache!', (string) $result->getBody()); + } + + /** + * Daily RSS - No bookmark + */ + public function testValidRssControllerInvokeNoBookmark(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('dailyrss', (string) $result->getBody()); + static::assertSame('Shaarli', $assignedVariables['title']); + static::assertSame('http://shaarli', $assignedVariables['index_url']); + static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']); + static::assertFalse($assignedVariables['hide_timestamps']); + static::assertCount(0, $assignedVariables['days']); + } + + protected static function generateContent(int $length): string + { + // bin2hex(random_bytes) generates string twice as long as given parameter + $length = (int) ceil($length / 2); + return bin2hex(random_bytes($length)); + } +} diff --git a/tests/front/controller/visitor/FeedControllerTest.php b/tests/front/controller/visitor/FeedControllerTest.php new file mode 100644 index 00000000..fd4679ea --- /dev/null +++ b/tests/front/controller/visitor/FeedControllerTest.php @@ -0,0 +1,151 @@ +createContainer(); + + $this->container->feedBuilder = $this->createMock(FeedBuilder::class); + + $this->controller = new FeedController($this->container); + } + + /** + * Feed Controller - RSS default behaviour + */ + public function testDefaultRssController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->feedBuilder->expects(static::once())->method('setLocale'); + $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); + $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('rss', $param['target']); + }) + ; + + $result = $this->controller->rss($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.rss', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } + + /** + * Feed Controller - ATOM default behaviour + */ + public function testDefaultAtomController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->feedBuilder->expects(static::once())->method('setLocale'); + $this->container->feedBuilder->expects(static::once())->method('setHideDates')->with(false); + $this->container->feedBuilder->expects(static::once())->method('setUsePermalinks')->with(true); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder->method('buildData')->willReturn(['content' => 'data']); + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('atom', $param['target']); + }) + ; + + $result = $this->controller->atom($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.atom', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } + + /** + * Feed Controller - ATOM with parameters + */ + public function testAtomControllerWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->method('getParams')->willReturn(['parameter' => 'value']); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->feedBuilder + ->method('buildData') + ->with('atom', ['parameter' => 'value']) + ->willReturn(['content' => 'data']) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): void { + static::assertSame('render_feed', $hook); + static::assertSame('data', $data['content']); + + static::assertArrayHasKey('loggedin', $param); + static::assertSame('atom', $param['target']); + }) + ; + + $result = $this->controller->atom($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString('application/atom', $result->getHeader('Content-Type')[0]); + static::assertSame('feed.atom', (string) $result->getBody()); + static::assertSame('data', $assignedVariables['content']); + } +} diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php new file mode 100644 index 00000000..bc3266b5 --- /dev/null +++ b/tests/front/controller/visitor/FrontControllerMockHelper.php @@ -0,0 +1,114 @@ +container = $this->createMock(ShaarliTestContainer::class); + } + + /** + * Initialize container's services used by tests + */ + protected function createValidContainerMockSet(): void + { + $this->container->loginManager = $this->createMock(LoginManager::class); + + // Config + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + return $default; + }); + + // PageBuilder + $this->container->pageBuilder = $this->createMock(PageBuilder::class); + $this->container->pageBuilder + ->method('render') + ->willReturnCallback(function (string $template): string { + return $template; + }) + ; + + // Plugin Manager + $this->container->pluginManager = $this->createMock(PluginManager::class); + + // BookmarkService + $this->container->bookmarkService = $this->createMock(BookmarkServiceInterface::class); + + // Formatter + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->method('getFormatter') + ->willReturnCallback(function (): BookmarkFormatter { + return new BookmarkRawFormatter($this->container->conf, true); + }) + ; + + // CacheManager + $this->container->pageCacheManager = $this->createMock(PageCacheManager::class); + + // SessionManager + $this->container->sessionManager = $this->createMock(SessionManager::class); + + // $_SERVER + $this->container->environment = [ + 'SERVER_NAME' => 'shaarli', + 'SERVER_PORT' => '80', + 'REQUEST_URI' => '/daily-rss', + ]; + } + + /** + * Pass a reference of an array which will be populated by `pageBuilder->assign` calls during execution. + * + * @param mixed $variables Array reference to populate. + */ + protected function assignTemplateVars(array &$variables): void + { + $this->container->pageBuilder + ->expects(static::atLeastOnce()) + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$variables) { + $variables[$key] = $value; + + return $this; + }) + ; + } + + /** + * Force to be used in PHPUnit context. + */ + protected abstract function createMock($originalClassName): MockObject; +} diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php new file mode 100644 index 00000000..9d223316 --- /dev/null +++ b/tests/front/controller/visitor/LoginControllerTest.php @@ -0,0 +1,144 @@ +createContainer(); + + $this->controller = new LoginController($this->container); + } + + public function testValidControllerInvoke(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); + $response = new Response(); + + $assignedVariables = []; + $this->container->pageBuilder + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { + $assignedVariables[$key] = $value; + + return $this; + }) + ; + + $this->container->loginManager->method('canLogin')->willReturn(true); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(200, $result->getStatusCode()); + static::assertSame('loginform', (string) $result->getBody()); + + static::assertSame('> referer', $assignedVariables['returnurl']); + static::assertSame(true, $assignedVariables['remember_user_default']); + static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); + } + + public function testValidControllerInvokeWithUserName(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); + $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>'); + $response = new Response(); + + $assignedVariables = []; + $this->container->pageBuilder + ->method('assign') + ->willReturnCallback(function ($key, $value) use (&$assignedVariables) { + $assignedVariables[$key] = $value; + + return $this; + }) + ; + + $this->container->loginManager->expects(static::once())->method('canLogin')->willReturn(true); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(200, $result->getStatusCode()); + static::assertSame('loginform', (string) $result->getBody()); + + static::assertSame('myUser>', $assignedVariables['username']); + static::assertSame('> referer', $assignedVariables['returnurl']); + static::assertSame(true, $assignedVariables['remember_user_default']); + static::assertSame('Login - Shaarli', $assignedVariables['pagetitle']); + } + + public function testLoginControllerWhileLoggedIn(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->loginManager->expects(static::once())->method('isLoggedIn')->willReturn(true); + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('Location')); + } + + public function testLoginControllerOpenShaarli(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $conf = $this->createMock(ConfigManager::class); + $conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'security.open_shaarli') { + return true; + } + return $default; + }); + $this->container->conf = $conf; + + $result = $this->controller->index($request, $response); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('Location')); + } + + public function testLoginControllerWhileBanned(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $this->container->loginManager->method('isLoggedIn')->willReturn(false); + $this->container->loginManager->method('canLogin')->willReturn(false); + + $this->expectException(LoginBannedException::class); + + $this->controller->index($request, $response); + } +} diff --git a/tests/front/controller/visitor/OpenSearchControllerTest.php b/tests/front/controller/visitor/OpenSearchControllerTest.php new file mode 100644 index 00000000..52475318 --- /dev/null +++ b/tests/front/controller/visitor/OpenSearchControllerTest.php @@ -0,0 +1,46 @@ +createContainer(); + + $this->controller = new OpenSearchController($this->container); + } + + public function testOpenSearchController(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertStringContainsString( + 'application/opensearchdescription+xml', + $result->getHeader('Content-Type')[0] + ); + static::assertSame('opensearch', (string) $result->getBody()); + static::assertSame('http://shaarli', $assignedVariables['serverurl']); + } +} diff --git a/tests/front/controller/visitor/PictureWallControllerTest.php b/tests/front/controller/visitor/PictureWallControllerTest.php new file mode 100644 index 00000000..7ac842cb --- /dev/null +++ b/tests/front/controller/visitor/PictureWallControllerTest.php @@ -0,0 +1,125 @@ +createContainer(); + + $this->controller = new PictureWallController($this->container); + } + + public function testValidControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request->expects(static::once())->method('getQueryParams')->willReturn([]); + $response = new Response(); + + // ConfigManager: thumbnails are enabled + $this->container->conf = $this->createMock(ConfigManager::class); + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'thumbnails.mode') { + return Thumbnailer::MODE_COMMON; + } + + return $default; + }); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + // Links dataset: 2 links with thumbnails + $this->container->bookmarkService + ->expects(static::once()) + ->method('search') + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + // Visibility is set through the container, not the call + static::assertNull($visibility); + + // No query parameters + if (count($parameters) === 0) { + return [ + (new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'), + (new Bookmark())->setId(2)->setUrl('http://url2.tld'), + (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'), + ]; + } + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_picwall', $hook); + static::assertArrayHasKey('linksToDisplay', $data); + static::assertCount(2, $data['linksToDisplay']); + static::assertSame(1, $data['linksToDisplay'][0]['id']); + static::assertSame(3, $data['linksToDisplay'][1]['id']); + static::assertArrayHasKey('loggedin', $param); + + return $data; + }); + + $result = $this->controller->index($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('picwall', (string) $result->getBody()); + static::assertSame('Picture wall - Shaarli', $assignedVariables['pagetitle']); + static::assertCount(2, $assignedVariables['linksToDisplay']); + + $link = $assignedVariables['linksToDisplay'][0]; + + static::assertSame(1, $link['id']); + static::assertSame('http://url.tld', $link['url']); + static::assertSame('thumb1', $link['thumbnail']); + + $link = $assignedVariables['linksToDisplay'][1]; + + static::assertSame(3, $link['id']); + static::assertSame('http://url3.tld', $link['url']); + static::assertSame('thumb2', $link['thumbnail']); + } + + public function testControllerWithThumbnailsDisabled(): void + { + $this->expectException(ThumbnailsDisabledException::class); + + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // ConfigManager: thumbnails are disabled + $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { + if ($parameter === 'thumbnails.mode') { + return Thumbnailer::MODE_NONE; + } + + return $default; + }); + + $this->controller->index($request, $response); + } +} diff --git a/tests/front/controller/visitor/ShaarliPublicControllerTest.php b/tests/front/controller/visitor/ShaarliPublicControllerTest.php new file mode 100644 index 00000000..e2e88da3 --- /dev/null +++ b/tests/front/controller/visitor/ShaarliPublicControllerTest.php @@ -0,0 +1,239 @@ +createContainer(); + + $this->controller = new class($this->container) extends ShaarliVisitorController + { + public function assignView(string $key, $value): ShaarliVisitorController + { + return parent::assignView($key, $value); + } + + public function render(string $template): string + { + return parent::render($template); + } + + public function redirectFromReferer( + Request $request, + Response $response, + array $loopTerms = [], + array $clearParams = [] + ): Response { + return parent::redirectFromReferer($request, $response, $loopTerms, $clearParams); + } + }; + $this->assignedValues = []; + + $this->request = $this->createMock(Request::class); + $this->request->method('getUri')->willReturnCallback(function (): Uri { + $uri = $this->createMock(Uri::class); + $uri->method('getBasePath')->willReturn('/subfolder'); + + return $uri; + }); + } + + public function testAssignView(): void + { + $this->createValidContainerMockSet(); + + $this->assignTemplateVars($this->assignedValues); + + $self = $this->controller->assignView('variableName', 'variableValue'); + + static::assertInstanceOf(ShaarliVisitorController::class, $self); + static::assertSame('variableValue', $this->assignedValues['variableName']); + } + + public function testRender(): void + { + $this->createValidContainerMockSet(); + + $this->assignTemplateVars($this->assignedValues); + + $this->container->bookmarkService + ->method('count') + ->willReturnCallback(function (string $visibility): int { + return $visibility === BookmarkFilter::$PRIVATE ? 5 : 10; + }) + ; + + $this->container->pluginManager + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array &$data, array $params): array { + return $data[$hook] = $params; + }); + $this->container->pluginManager->method('getErrors')->willReturn(['error']); + + $this->container->loginManager->method('isLoggedIn')->willReturn(true); + + $render = $this->controller->render('templateName'); + + static::assertSame('templateName', $render); + + static::assertSame(10, $this->assignedValues['linkcount']); + static::assertSame(5, $this->assignedValues['privateLinkcount']); + static::assertSame(['error'], $this->assignedValues['plugin_errors']); + + static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']); + static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_header']['render_header']['target']); + static::assertTrue($this->assignedValues['plugins_header']['render_header']['loggedin']); + static::assertSame('templateName', $this->assignedValues['plugins_footer']['render_footer']['target']); + static::assertTrue($this->assignedValues['plugins_footer']['render_footer']['loggedin']); + } + + /** + * Test redirectFromReferer() - Default behaviour + */ + public function testRedirectFromRefererDefault(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term not matched in the referer + */ + public function testRedirectFromRefererWithUnmatchedLoopTerm(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its path -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInPath(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'controller']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query parameters -> redirect to default + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'other']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its query value + * -> we do not block redirection for query parameter values. + */ + public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['nope', 'param']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching the referer in its domain name + * -> we do not block redirection for shaarli's hosts + */ + public function testRedirectFromRefererWithLoopTermInDomain(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['shaarli']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?query=param&other=2'], $result->getHeader('location')); + } + + /** + * Test redirectFromReferer() - With a loop term matching a query parameter AND clear this query param + * -> the param should be cleared before checking if it matches the redir loop terms + */ + public function testRedirectFromRefererWithMatchingClearedParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; + + $response = new Response(); + + $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']); + + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location')); + } +} diff --git a/tests/front/controller/visitor/TagCloudControllerTest.php b/tests/front/controller/visitor/TagCloudControllerTest.php new file mode 100644 index 00000000..e636d496 --- /dev/null +++ b/tests/front/controller/visitor/TagCloudControllerTest.php @@ -0,0 +1,381 @@ +createContainer(); + + $this->controller = new TagCloudController($this->container); + } + + /** + * Tag Cloud - default parameters + */ + public function testValidCloudControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $allTags = [ + 'ghi' => 1, + 'abc' => 3, + 'def' => 12, + ]; + $expectedOrder = ['abc', 'def', 'ghi']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function () use ($allTags): array { + return $allTags; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(3, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->cloud($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(3, $assignedVariables['tags']); + static::assertSame($expectedOrder, array_keys($assignedVariables['tags'])); + + foreach ($allTags as $tag => $count) { + static::assertArrayHasKey($tag, $assignedVariables['tags']); + static::assertSame($count, $assignedVariables['tags'][$tag]['count']); + static::assertGreaterThan(0, $assignedVariables['tags'][$tag]['size']); + static::assertLessThan(5, $assignedVariables['tags'][$tag]['size']); + } + } + + /** + * Tag Cloud - Additional parameters: + * - logged in + * - visibility private + * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) + */ + public function testValidCloudControllerInvokeWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request + ->method('getQueryParam') + ->with() + ->willReturnCallback(function (string $key): ?string { + if ('searchtags' === $key) { + return 'ghi def'; + } + + return null; + }) + ; + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->loginManager->method('isLoggedin')->willReturn(true); + $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) + ->willReturnCallback(function (): array { + return ['abc' => 3]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('ghi def', $data['search_tags']); + static::assertCount(1, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->cloud($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('ghi def - Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('ghi def', $assignedVariables['search_tags']); + static::assertCount(1, $assignedVariables['tags']); + + static::assertArrayHasKey('abc', $assignedVariables['tags']); + static::assertSame(3, $assignedVariables['tags']['abc']['count']); + static::assertGreaterThan(0, $assignedVariables['tags']['abc']['size']); + static::assertLessThan(5, $assignedVariables['tags']['abc']['size']); + } + + /** + * Tag Cloud - empty + */ + public function testEmptyCloud(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_tagcloud', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(0, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->cloud($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.cloud', (string) $result->getBody()); + static::assertSame('Tag cloud - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(0, $assignedVariables['tags']); + } + + /** + * Tag List - Default sort is by usage DESC + */ + public function testValidListControllerInvokeDefault(): void + { + $this->createValidContainerMockSet(); + + $allTags = [ + 'def' => 12, + 'abc' => 3, + 'ghi' => 1, + ]; + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function () use ($allTags): array { + return $allTags; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(3, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(3, $assignedVariables['tags']); + + foreach ($allTags as $tag => $count) { + static::assertSame($count, $assignedVariables['tags'][$tag]); + } + } + + /** + * Tag List - Additional parameters: + * - logged in + * - visibility private + * - search tags: `ghi` and `def` (note that filtered tags are not displayed anymore) + * - sort alphabetically + */ + public function testValidListControllerInvokeWithParameters(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $request + ->method('getQueryParam') + ->with() + ->willReturnCallback(function (string $key): ?string { + if ('searchtags' === $key) { + return 'ghi def'; + } elseif ('sort' === $key) { + return 'alpha'; + } + + return null; + }) + ; + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->loginManager->method('isLoggedin')->willReturn(true); + $this->container->sessionManager->expects(static::once())->method('getSessionParameter')->willReturn('private'); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with(['ghi', 'def'], BookmarkFilter::$PRIVATE) + ->willReturnCallback(function (): array { + return ['abc' => 3]; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('ghi def', $data['search_tags']); + static::assertCount(1, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('ghi def - Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('ghi def', $assignedVariables['search_tags']); + static::assertCount(1, $assignedVariables['tags']); + static::assertSame(3, $assignedVariables['tags']['abc']); + } + + /** + * Tag List - empty + */ + public function testEmptyList(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + // Save RainTPL assigned variables + $assignedVariables = []; + $this->assignTemplateVars($assignedVariables); + + $this->container->bookmarkService + ->expects(static::once()) + ->method('bookmarksCountPerTag') + ->with([], null) + ->willReturnCallback(function (array $parameters, ?string $visibility): array { + return []; + }) + ; + + // Make sure that PluginManager hook is triggered + $this->container->pluginManager + ->expects(static::at(0)) + ->method('executeHooks') + ->willReturnCallback(function (string $hook, array $data, array $param): array { + static::assertSame('render_taglist', $hook); + static::assertSame('', $data['search_tags']); + static::assertCount(0, $data['tags']); + + static::assertArrayHasKey('loggedin', $param); + + return $data; + }) + ; + + $result = $this->controller->list($request, $response); + + static::assertSame(200, $result->getStatusCode()); + static::assertSame('tag.list', (string) $result->getBody()); + static::assertSame('Tag list - Shaarli', $assignedVariables['pagetitle']); + + static::assertSame('', $assignedVariables['search_tags']); + static::assertCount(0, $assignedVariables['tags']); + } +} diff --git a/tests/front/controller/visitor/TagControllerTest.php b/tests/front/controller/visitor/TagControllerTest.php new file mode 100644 index 00000000..9a2b1f71 --- /dev/null +++ b/tests/front/controller/visitor/TagControllerTest.php @@ -0,0 +1,241 @@ +createContainer(); + + $this->controller = new TagController($this->container); + } + + public function testAddTagWithReferer(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagWithRefererAndExistingSearch(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagWithoutRefererAndExistingSearch(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagRemoveLegacyQueryParam(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagResetPagination(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); + } + + public function testAddTagWithRefererAndEmptySearch(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['newTag' => 'abc']; + + $result = $this->controller->addTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=abc'], $result->getHeader('location')); + } + + public function testAddTagWithoutNewTagWithReferer(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); + } + + public function testAddTagWithoutNewTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->addTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutMatchingTag(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtags=def'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTagsearch(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $tags = ['tag' => 'abc']; + + $result = $this->controller->removeTag($request, $response, $tags); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTag(): void + { + $this->createValidContainerMockSet(); + + $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc']; + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->removeTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['/controller/?searchtag=abc'], $result->getHeader('location')); + } + + public function testRemoveTagWithoutTagWithoutReferer(): void + { + $this->createValidContainerMockSet(); + + $request = $this->createMock(Request::class); + $response = new Response(); + + $result = $this->controller->removeTag($request, $response, []); + + static::assertInstanceOf(Response::class, $result); + static::assertSame(302, $result->getStatusCode()); + static::assertSame(['./'], $result->getHeader('location')); + } +} -- cgit v1.2.3