aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/HistoryTest.php8
-rw-r--r--tests/UtilsTest.php36
-rw-r--r--tests/api/controllers/info/InfoTest.php4
-rw-r--r--tests/api/controllers/links/DeleteLinkTest.php9
-rw-r--r--tests/api/controllers/links/GetLinkIdTest.php4
-rw-r--r--tests/api/controllers/links/GetLinksTest.php6
-rw-r--r--tests/api/controllers/links/PostLinkTest.php20
-rw-r--r--tests/api/controllers/links/PutLinkTest.php4
-rw-r--r--tests/api/controllers/tags/DeleteTagTest.php11
-rw-r--r--tests/api/controllers/tags/GetTagNameTest.php4
-rw-r--r--tests/api/controllers/tags/GetTagsTest.php4
-rw-r--r--tests/api/controllers/tags/PutTagTest.php4
-rw-r--r--tests/bookmark/BookmarkArrayTest.php13
-rw-r--r--tests/bookmark/BookmarkFileServiceTest.php259
-rw-r--r--tests/bookmark/BookmarkFilterTest.php46
-rw-r--r--tests/bookmark/BookmarkInitializerTest.php13
-rw-r--r--tests/bookmark/BookmarkTest.php107
-rw-r--r--tests/bookmark/LinkUtilsTest.php446
-rw-r--r--tests/bootstrap.php4
-rw-r--r--tests/container/ContainerBuilderTest.php7
-rw-r--r--tests/feed/FeedBuilderTest.php4
-rw-r--r--tests/formatter/BookmarkDefaultFormatterTest.php135
-rw-r--r--tests/formatter/BookmarkMarkdownExtraFormatterTest.php162
-rw-r--r--tests/front/controller/admin/ConfigureControllerTest.php2
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php47
-rw-r--r--tests/front/controller/admin/ManageTagControllerTest.php136
-rw-r--r--tests/front/controller/admin/ServerControllerTest.php184
-rw-r--r--tests/front/controller/admin/ShaareAddControllerTest.php97
-rw-r--r--tests/front/controller/admin/ShaareManageControllerTest/ChangeVisibilityBookmarkTest.php (renamed from tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php)8
-rw-r--r--tests/front/controller/admin/ShaareManageControllerTest/DeleteBookmarkTest.php (renamed from tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php)18
-rw-r--r--tests/front/controller/admin/ShaareManageControllerTest/PinBookmarkTest.php (renamed from tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php)8
-rw-r--r--tests/front/controller/admin/ShaareManageControllerTest/SharePrivateTest.php139
-rw-r--r--tests/front/controller/admin/ShaarePublishControllerTest/DisplayCreateBatchFormTest.php63
-rw-r--r--tests/front/controller/admin/ShaarePublishControllerTest/DisplayCreateFormTest.php (renamed from tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php)136
-rw-r--r--tests/front/controller/admin/ShaarePublishControllerTest/DisplayEditFormTest.php (renamed from tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php)10
-rw-r--r--tests/front/controller/admin/ShaarePublishControllerTest/SaveBookmarkTest.php (renamed from tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php)83
-rw-r--r--tests/front/controller/admin/ThumbnailsControllerTest.php4
-rw-r--r--tests/front/controller/visitor/BookmarkListControllerTest.php94
-rw-r--r--tests/front/controller/visitor/DailyControllerTest.php412
-rw-r--r--tests/front/controller/visitor/ErrorControllerTest.php29
-rw-r--r--tests/front/controller/visitor/FrontControllerMockHelper.php4
-rw-r--r--tests/front/controller/visitor/InstallControllerTest.php9
-rw-r--r--tests/front/controller/visitor/LoginControllerTest.php2
-rw-r--r--tests/front/controller/visitor/TagCloudControllerTest.php12
-rw-r--r--tests/front/controller/visitor/TagControllerTest.php6
-rw-r--r--tests/helper/ApplicationUtilsTest.php (renamed from tests/ApplicationUtilsTest.php)65
-rw-r--r--tests/helper/DailyPageHelperTest.php262
-rw-r--r--tests/helper/FileUtilsTest.php (renamed from tests/FileUtilsTest.php)91
-rw-r--r--tests/http/MetadataRetrieverTest.php154
-rw-r--r--tests/legacy/LegacyLinkDBTest.php12
-rw-r--r--tests/legacy/LegacyUpdaterTest.php16
-rw-r--r--tests/netscape/BookmarkExportTest.php4
-rw-r--r--tests/netscape/BookmarkImportTest.php45
-rw-r--r--tests/plugins/PluginWallabagTest.php35
-rw-r--r--tests/security/BanManagerTest.php5
-rw-r--r--tests/security/LoginManagerTest.php51
-rw-r--r--tests/security/SessionManagerTest.php5
-rw-r--r--tests/updater/UpdaterTest.php20
-rw-r--r--tests/utils/FakeApplicationUtils.php2
-rw-r--r--tests/utils/FakeConfigManager.php10
-rw-r--r--tests/utils/ReferenceHistory.php2
-rw-r--r--tests/utils/ReferenceLinkDB.php2
62 files changed, 2992 insertions, 602 deletions
diff --git a/tests/HistoryTest.php b/tests/HistoryTest.php
index 6dc0e5b7..e810104e 100644
--- a/tests/HistoryTest.php
+++ b/tests/HistoryTest.php
@@ -89,14 +89,6 @@ class HistoryTest extends \Shaarli\TestCase
89 $this->assertEquals(History::CREATED, $actual['event']); 89 $this->assertEquals(History::CREATED, $actual['event']);
90 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']); 90 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
91 $this->assertEquals(1, $actual['id']); 91 $this->assertEquals(1, $actual['id']);
92
93 $history = new History(self::$historyFilePath);
94 $bookmark = (new Bookmark())->setId('str');
95 $history->addLink($bookmark);
96 $actual = $history->getHistory()[0];
97 $this->assertEquals(History::CREATED, $actual['event']);
98 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
99 $this->assertEquals('str', $actual['id']);
100 } 92 }
101 93
102// /** 94// /**
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
index 6e787d7f..59dca75f 100644
--- a/tests/UtilsTest.php
+++ b/tests/UtilsTest.php
@@ -63,41 +63,25 @@ class UtilsTest extends \Shaarli\TestCase
63 } 63 }
64 64
65 /** 65 /**
66 * Log a message to a file - IPv4 client address 66 * Format a log a message - IPv4 client address
67 */ 67 */
68 public function testLogmIp4() 68 public function testFormatLogIp4()
69 { 69 {
70 $logMessage = 'IPv4 client connected'; 70 $message = 'IPv4 client connected';
71 logm(self::$testLogFile, '127.0.0.1', $logMessage); 71 $log = format_log($message, '127.0.0.1');
72 list($date, $ip, $message) = $this->getLastLogEntry();
73 72
74 $this->assertInstanceOf( 73 static::assertSame('- 127.0.0.1 - IPv4 client connected', $log);
75 'DateTime',
76 DateTime::createFromFormat(self::$dateFormat, $date)
77 );
78 $this->assertTrue(
79 filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false
80 );
81 $this->assertEquals($logMessage, $message);
82 } 74 }
83 75
84 /** 76 /**
85 * Log a message to a file - IPv6 client address 77 * Format a log a message - IPv6 client address
86 */ 78 */
87 public function testLogmIp6() 79 public function testFormatLogIp6()
88 { 80 {
89 $logMessage = 'IPv6 client connected'; 81 $message = 'IPv6 client connected';
90 logm(self::$testLogFile, '2001:db8::ff00:42:8329', $logMessage); 82 $log = format_log($message, '2001:db8::ff00:42:8329');
91 list($date, $ip, $message) = $this->getLastLogEntry();
92 83
93 $this->assertInstanceOf( 84 static::assertSame('- 2001:db8::ff00:42:8329 - IPv6 client connected', $log);
94 'DateTime',
95 DateTime::createFromFormat(self::$dateFormat, $date)
96 );
97 $this->assertTrue(
98 filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false
99 );
100 $this->assertEquals($logMessage, $message);
101 } 85 }
102 86
103 /** 87 /**
diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php
index 1598e1e8..10b29ab2 100644
--- a/tests/api/controllers/info/InfoTest.php
+++ b/tests/api/controllers/info/InfoTest.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2namespace Shaarli\Api\Controllers; 2namespace Shaarli\Api\Controllers;
3 3
4use malkusch\lock\mutex\NoMutex;
4use Shaarli\Bookmark\BookmarkFileService; 5use Shaarli\Bookmark\BookmarkFileService;
5use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
6use Shaarli\History; 7use Shaarli\History;
@@ -49,6 +50,7 @@ class InfoTest extends TestCase
49 */ 50 */
50 protected function setUp(): void 51 protected function setUp(): void
51 { 52 {
53 $mutex = new NoMutex();
52 $this->conf = new ConfigManager('tests/utils/config/configJson'); 54 $this->conf = new ConfigManager('tests/utils/config/configJson');
53 $this->conf->set('resource.datastore', self::$testDatastore); 55 $this->conf->set('resource.datastore', self::$testDatastore);
54 $this->refDB = new \ReferenceLinkDB(); 56 $this->refDB = new \ReferenceLinkDB();
@@ -58,7 +60,7 @@ class InfoTest extends TestCase
58 60
59 $this->container = new Container(); 61 $this->container = new Container();
60 $this->container['conf'] = $this->conf; 62 $this->container['conf'] = $this->conf;
61 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 63 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
62 $this->container['history'] = null; 64 $this->container['history'] = null;
63 65
64 $this->controller = new Info($this->container); 66 $this->controller = new Info($this->container);
diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php
index cf9464f0..805c9be3 100644
--- a/tests/api/controllers/links/DeleteLinkTest.php
+++ b/tests/api/controllers/links/DeleteLinkTest.php
@@ -3,6 +3,7 @@
3 3
4namespace Shaarli\Api\Controllers; 4namespace Shaarli\Api\Controllers;
5 5
6use malkusch\lock\mutex\NoMutex;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
8use Shaarli\History; 9use Shaarli\History;
@@ -53,11 +54,15 @@ class DeleteLinkTest extends \Shaarli\TestCase
53 */ 54 */
54 protected $controller; 55 protected $controller;
55 56
57 /** @var NoMutex */
58 protected $mutex;
59
56 /** 60 /**
57 * Before each test, instantiate a new Api with its config, plugins and bookmarks. 61 * Before each test, instantiate a new Api with its config, plugins and bookmarks.
58 */ 62 */
59 protected function setUp(): void 63 protected function setUp(): void
60 { 64 {
65 $this->mutex = new NoMutex();
61 $this->conf = new ConfigManager('tests/utils/config/configJson'); 66 $this->conf = new ConfigManager('tests/utils/config/configJson');
62 $this->conf->set('resource.datastore', self::$testDatastore); 67 $this->conf->set('resource.datastore', self::$testDatastore);
63 $this->refDB = new \ReferenceLinkDB(); 68 $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +70,7 @@ class DeleteLinkTest extends \Shaarli\TestCase
65 $refHistory = new \ReferenceHistory(); 70 $refHistory = new \ReferenceHistory();
66 $refHistory->write(self::$testHistory); 71 $refHistory->write(self::$testHistory);
67 $this->history = new History(self::$testHistory); 72 $this->history = new History(self::$testHistory);
68 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 73 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
69 74
70 $this->container = new Container(); 75 $this->container = new Container();
71 $this->container['conf'] = $this->conf; 76 $this->container['conf'] = $this->conf;
@@ -100,7 +105,7 @@ class DeleteLinkTest extends \Shaarli\TestCase
100 $this->assertEquals(204, $response->getStatusCode()); 105 $this->assertEquals(204, $response->getStatusCode());
101 $this->assertEmpty((string) $response->getBody()); 106 $this->assertEmpty((string) $response->getBody());
102 107
103 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 108 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
104 $this->assertFalse($this->bookmarkService->exists($id)); 109 $this->assertFalse($this->bookmarkService->exists($id));
105 110
106 $historyEntry = $this->history->getHistory()[0]; 111 $historyEntry = $this->history->getHistory()[0];
diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php
index 99dc606f..1ec56ef3 100644
--- a/tests/api/controllers/links/GetLinkIdTest.php
+++ b/tests/api/controllers/links/GetLinkIdTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\Bookmark; 6use Shaarli\Bookmark\Bookmark;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -57,6 +58,7 @@ class GetLinkIdTest extends \Shaarli\TestCase
57 */ 58 */
58 protected function setUp(): void 59 protected function setUp(): void
59 { 60 {
61 $mutex = new NoMutex();
60 $this->conf = new ConfigManager('tests/utils/config/configJson'); 62 $this->conf = new ConfigManager('tests/utils/config/configJson');
61 $this->conf->set('resource.datastore', self::$testDatastore); 63 $this->conf->set('resource.datastore', self::$testDatastore);
62 $this->refDB = new \ReferenceLinkDB(); 64 $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +67,7 @@ class GetLinkIdTest extends \Shaarli\TestCase
65 67
66 $this->container = new Container(); 68 $this->container = new Container();
67 $this->container['conf'] = $this->conf; 69 $this->container['conf'] = $this->conf;
68 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 70 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
69 $this->container['history'] = null; 71 $this->container['history'] = null;
70 72
71 $this->controller = new Links($this->container); 73 $this->controller = new Links($this->container);
diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php
index ca1bfc63..b1c46ee2 100644
--- a/tests/api/controllers/links/GetLinksTest.php
+++ b/tests/api/controllers/links/GetLinksTest.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2namespace Shaarli\Api\Controllers; 2namespace Shaarli\Api\Controllers;
3 3
4use malkusch\lock\mutex\NoMutex;
4use Shaarli\Bookmark\Bookmark; 5use Shaarli\Bookmark\Bookmark;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Bookmark\LinkDB; 7use Shaarli\Bookmark\LinkDB;
@@ -57,6 +58,7 @@ class GetLinksTest extends \Shaarli\TestCase
57 */ 58 */
58 protected function setUp(): void 59 protected function setUp(): void
59 { 60 {
61 $mutex = new NoMutex();
60 $this->conf = new ConfigManager('tests/utils/config/configJson'); 62 $this->conf = new ConfigManager('tests/utils/config/configJson');
61 $this->conf->set('resource.datastore', self::$testDatastore); 63 $this->conf->set('resource.datastore', self::$testDatastore);
62 $this->refDB = new \ReferenceLinkDB(); 64 $this->refDB = new \ReferenceLinkDB();
@@ -65,7 +67,7 @@ class GetLinksTest extends \Shaarli\TestCase
65 67
66 $this->container = new Container(); 68 $this->container = new Container();
67 $this->container['conf'] = $this->conf; 69 $this->container['conf'] = $this->conf;
68 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 70 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
69 $this->container['history'] = null; 71 $this->container['history'] = null;
70 72
71 $this->controller = new Links($this->container); 73 $this->controller = new Links($this->container);
@@ -396,7 +398,7 @@ class GetLinksTest extends \Shaarli\TestCase
396 $response = $this->controller->getLinks($request, new Response()); 398 $response = $this->controller->getLinks($request, new Response());
397 $this->assertEquals(200, $response->getStatusCode()); 399 $this->assertEquals(200, $response->getStatusCode());
398 $data = json_decode((string) $response->getBody(), true); 400 $data = json_decode((string) $response->getBody(), true);
399 $this->assertEquals(4, count($data)); 401 $this->assertEquals(5, count($data));
400 $this->assertEquals(6, $data[0]['id']); 402 $this->assertEquals(6, $data[0]['id']);
401 403
402 // wildcard: placeholder at the middle 404 // wildcard: placeholder at the middle
diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php
index fe3de66f..e12f803b 100644
--- a/tests/api/controllers/links/PostLinkTest.php
+++ b/tests/api/controllers/links/PostLinkTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\Bookmark; 6use Shaarli\Bookmark\Bookmark;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -72,6 +73,7 @@ class PostLinkTest extends TestCase
72 */ 73 */
73 protected function setUp(): void 74 protected function setUp(): void
74 { 75 {
76 $mutex = new NoMutex();
75 $this->conf = new ConfigManager('tests/utils/config/configJson'); 77 $this->conf = new ConfigManager('tests/utils/config/configJson');
76 $this->conf->set('resource.datastore', self::$testDatastore); 78 $this->conf->set('resource.datastore', self::$testDatastore);
77 $this->refDB = new \ReferenceLinkDB(); 79 $this->refDB = new \ReferenceLinkDB();
@@ -79,7 +81,7 @@ class PostLinkTest extends TestCase
79 $refHistory = new \ReferenceHistory(); 81 $refHistory = new \ReferenceHistory();
80 $refHistory->write(self::$testHistory); 82 $refHistory->write(self::$testHistory);
81 $this->history = new History(self::$testHistory); 83 $this->history = new History(self::$testHistory);
82 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 84 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
83 85
84 $this->container = new Container(); 86 $this->container = new Container();
85 $this->container['conf'] = $this->conf; 87 $this->container['conf'] = $this->conf;
@@ -90,8 +92,8 @@ class PostLinkTest extends TestCase
90 92
91 $mock = $this->createMock(Router::class); 93 $mock = $this->createMock(Router::class);
92 $mock->expects($this->any()) 94 $mock->expects($this->any())
93 ->method('relativePathFor') 95 ->method('pathFor')
94 ->willReturn('api/v1/bookmarks/1'); 96 ->willReturn('/api/v1/bookmarks/1');
95 97
96 // affect @property-read... seems to work 98 // affect @property-read... seems to work
97 $this->controller->getCi()->router = $mock; 99 $this->controller->getCi()->router = $mock;
@@ -126,7 +128,7 @@ class PostLinkTest extends TestCase
126 128
127 $response = $this->controller->postLink($request, new Response()); 129 $response = $this->controller->postLink($request, new Response());
128 $this->assertEquals(201, $response->getStatusCode()); 130 $this->assertEquals(201, $response->getStatusCode());
129 $this->assertEquals('api/v1/bookmarks/1', $response->getHeader('Location')[0]); 131 $this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
130 $data = json_decode((string) $response->getBody(), true); 132 $data = json_decode((string) $response->getBody(), true);
131 $this->assertEquals(self::NB_FIELDS_LINK, count($data)); 133 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
132 $this->assertEquals(43, $data['id']); 134 $this->assertEquals(43, $data['id']);
@@ -160,6 +162,8 @@ class PostLinkTest extends TestCase
160 'description' => 'shaare description', 162 'description' => 'shaare description',
161 'tags' => ['one', 'two'], 163 'tags' => ['one', 'two'],
162 'private' => true, 164 'private' => true,
165 'created' => '2015-05-05T12:30:00+03:00',
166 'updated' => '2016-06-05T14:32:10+03:00',
163 ]; 167 ];
164 $env = Environment::mock([ 168 $env = Environment::mock([
165 'REQUEST_METHOD' => 'POST', 169 'REQUEST_METHOD' => 'POST',
@@ -171,7 +175,7 @@ class PostLinkTest extends TestCase
171 $response = $this->controller->postLink($request, new Response()); 175 $response = $this->controller->postLink($request, new Response());
172 176
173 $this->assertEquals(201, $response->getStatusCode()); 177 $this->assertEquals(201, $response->getStatusCode());
174 $this->assertEquals('api/v1/bookmarks/1', $response->getHeader('Location')[0]); 178 $this->assertEquals('/api/v1/bookmarks/1', $response->getHeader('Location')[0]);
175 $data = json_decode((string) $response->getBody(), true); 179 $data = json_decode((string) $response->getBody(), true);
176 $this->assertEquals(self::NB_FIELDS_LINK, count($data)); 180 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
177 $this->assertEquals(43, $data['id']); 181 $this->assertEquals(43, $data['id']);
@@ -181,10 +185,8 @@ class PostLinkTest extends TestCase
181 $this->assertEquals($link['description'], $data['description']); 185 $this->assertEquals($link['description'], $data['description']);
182 $this->assertEquals($link['tags'], $data['tags']); 186 $this->assertEquals($link['tags'], $data['tags']);
183 $this->assertEquals(true, $data['private']); 187 $this->assertEquals(true, $data['private']);
184 $this->assertTrue( 188 $this->assertSame($link['created'], $data['created']);
185 new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created']) 189 $this->assertSame($link['updated'], $data['updated']);
186 );
187 $this->assertEquals('', $data['updated']);
188 } 190 }
189 191
190 /** 192 /**
diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php
index a2e87c59..240ee323 100644
--- a/tests/api/controllers/links/PutLinkTest.php
+++ b/tests/api/controllers/links/PutLinkTest.php
@@ -3,6 +3,7 @@
3 3
4namespace Shaarli\Api\Controllers; 4namespace Shaarli\Api\Controllers;
5 5
6use malkusch\lock\mutex\NoMutex;
6use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
7use Shaarli\Bookmark\BookmarkFileService; 8use Shaarli\Bookmark\BookmarkFileService;
8use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
@@ -64,6 +65,7 @@ class PutLinkTest extends \Shaarli\TestCase
64 */ 65 */
65 protected function setUp(): void 66 protected function setUp(): void
66 { 67 {
68 $mutex = new NoMutex();
67 $this->conf = new ConfigManager('tests/utils/config/configJson'); 69 $this->conf = new ConfigManager('tests/utils/config/configJson');
68 $this->conf->set('resource.datastore', self::$testDatastore); 70 $this->conf->set('resource.datastore', self::$testDatastore);
69 $this->refDB = new \ReferenceLinkDB(); 71 $this->refDB = new \ReferenceLinkDB();
@@ -71,7 +73,7 @@ class PutLinkTest extends \Shaarli\TestCase
71 $refHistory = new \ReferenceHistory(); 73 $refHistory = new \ReferenceHistory();
72 $refHistory->write(self::$testHistory); 74 $refHistory->write(self::$testHistory);
73 $this->history = new History(self::$testHistory); 75 $this->history = new History(self::$testHistory);
74 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 76 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
75 77
76 $this->container = new Container(); 78 $this->container = new Container();
77 $this->container['conf'] = $this->conf; 79 $this->container['conf'] = $this->conf;
diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php
index 1326eb47..37f07229 100644
--- a/tests/api/controllers/tags/DeleteTagTest.php
+++ b/tests/api/controllers/tags/DeleteTagTest.php
@@ -3,6 +3,7 @@
3 3
4namespace Shaarli\Api\Controllers; 4namespace Shaarli\Api\Controllers;
5 5
6use malkusch\lock\mutex\NoMutex;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Bookmark\LinkDB; 8use Shaarli\Bookmark\LinkDB;
8use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
@@ -54,11 +55,15 @@ class DeleteTagTest extends \Shaarli\TestCase
54 */ 55 */
55 protected $controller; 56 protected $controller;
56 57
58 /** @var NoMutex */
59 protected $mutex;
60
57 /** 61 /**
58 * Before each test, instantiate a new Api with its config, plugins and bookmarks. 62 * Before each test, instantiate a new Api with its config, plugins and bookmarks.
59 */ 63 */
60 protected function setUp(): void 64 protected function setUp(): void
61 { 65 {
66 $this->mutex = new NoMutex();
62 $this->conf = new ConfigManager('tests/utils/config/configJson'); 67 $this->conf = new ConfigManager('tests/utils/config/configJson');
63 $this->conf->set('resource.datastore', self::$testDatastore); 68 $this->conf->set('resource.datastore', self::$testDatastore);
64 $this->refDB = new \ReferenceLinkDB(); 69 $this->refDB = new \ReferenceLinkDB();
@@ -66,7 +71,7 @@ class DeleteTagTest extends \Shaarli\TestCase
66 $refHistory = new \ReferenceHistory(); 71 $refHistory = new \ReferenceHistory();
67 $refHistory->write(self::$testHistory); 72 $refHistory->write(self::$testHistory);
68 $this->history = new History(self::$testHistory); 73 $this->history = new History(self::$testHistory);
69 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 74 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
70 75
71 $this->container = new Container(); 76 $this->container = new Container();
72 $this->container['conf'] = $this->conf; 77 $this->container['conf'] = $this->conf;
@@ -102,7 +107,7 @@ class DeleteTagTest extends \Shaarli\TestCase
102 $this->assertEquals(204, $response->getStatusCode()); 107 $this->assertEquals(204, $response->getStatusCode());
103 $this->assertEmpty((string) $response->getBody()); 108 $this->assertEmpty((string) $response->getBody());
104 109
105 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 110 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
106 $tags = $this->bookmarkService->bookmarksCountPerTag(); 111 $tags = $this->bookmarkService->bookmarksCountPerTag();
107 $this->assertFalse(isset($tags[$tagName])); 112 $this->assertFalse(isset($tags[$tagName]));
108 113
@@ -136,7 +141,7 @@ class DeleteTagTest extends \Shaarli\TestCase
136 $this->assertEquals(204, $response->getStatusCode()); 141 $this->assertEquals(204, $response->getStatusCode());
137 $this->assertEmpty((string) $response->getBody()); 142 $this->assertEmpty((string) $response->getBody());
138 143
139 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 144 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
140 $tags = $this->bookmarkService->bookmarksCountPerTag(); 145 $tags = $this->bookmarkService->bookmarksCountPerTag();
141 $this->assertFalse(isset($tags[$tagName])); 146 $this->assertFalse(isset($tags[$tagName]));
142 $this->assertTrue($tags[strtolower($tagName)] > 0); 147 $this->assertTrue($tags[strtolower($tagName)] > 0);
diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php
index 9c05954b..878de5a4 100644
--- a/tests/api/controllers/tags/GetTagNameTest.php
+++ b/tests/api/controllers/tags/GetTagNameTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Bookmark\LinkDB; 7use Shaarli\Bookmark\LinkDB;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -55,6 +56,7 @@ class GetTagNameTest extends \Shaarli\TestCase
55 */ 56 */
56 protected function setUp(): void 57 protected function setUp(): void
57 { 58 {
59 $mutex = new NoMutex();
58 $this->conf = new ConfigManager('tests/utils/config/configJson'); 60 $this->conf = new ConfigManager('tests/utils/config/configJson');
59 $this->conf->set('resource.datastore', self::$testDatastore); 61 $this->conf->set('resource.datastore', self::$testDatastore);
60 $this->refDB = new \ReferenceLinkDB(); 62 $this->refDB = new \ReferenceLinkDB();
@@ -63,7 +65,7 @@ class GetTagNameTest extends \Shaarli\TestCase
63 65
64 $this->container = new Container(); 66 $this->container = new Container();
65 $this->container['conf'] = $this->conf; 67 $this->container['conf'] = $this->conf;
66 $this->container['db'] = new BookmarkFileService($this->conf, $history, true); 68 $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true);
67 $this->container['history'] = null; 69 $this->container['history'] = null;
68 70
69 $this->controller = new Tags($this->container); 71 $this->controller = new Tags($this->container);
diff --git a/tests/api/controllers/tags/GetTagsTest.php b/tests/api/controllers/tags/GetTagsTest.php
index 3459fdfa..b565a8c4 100644
--- a/tests/api/controllers/tags/GetTagsTest.php
+++ b/tests/api/controllers/tags/GetTagsTest.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2namespace Shaarli\Api\Controllers; 2namespace Shaarli\Api\Controllers;
3 3
4use malkusch\lock\mutex\NoMutex;
4use Shaarli\Bookmark\BookmarkFileService; 5use Shaarli\Bookmark\BookmarkFileService;
5use Shaarli\Bookmark\LinkDB; 6use Shaarli\Bookmark\LinkDB;
6use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
@@ -59,13 +60,14 @@ class GetTagsTest extends \Shaarli\TestCase
59 */ 60 */
60 protected function setUp(): void 61 protected function setUp(): void
61 { 62 {
63 $mutex = new NoMutex();
62 $this->conf = new ConfigManager('tests/utils/config/configJson'); 64 $this->conf = new ConfigManager('tests/utils/config/configJson');
63 $this->conf->set('resource.datastore', self::$testDatastore); 65 $this->conf->set('resource.datastore', self::$testDatastore);
64 $this->refDB = new \ReferenceLinkDB(); 66 $this->refDB = new \ReferenceLinkDB();
65 $this->refDB->write(self::$testDatastore); 67 $this->refDB->write(self::$testDatastore);
66 $history = new History('sandbox/history.php'); 68 $history = new History('sandbox/history.php');
67 69
68 $this->bookmarkService = new BookmarkFileService($this->conf, $history, true); 70 $this->bookmarkService = new BookmarkFileService($this->conf, $history, $mutex, true);
69 71
70 $this->container = new Container(); 72 $this->container = new Container();
71 $this->container['conf'] = $this->conf; 73 $this->container['conf'] = $this->conf;
diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php
index 74edde78..c73f6d3b 100644
--- a/tests/api/controllers/tags/PutTagTest.php
+++ b/tests/api/controllers/tags/PutTagTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Api\Controllers; 3namespace Shaarli\Api\Controllers;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Api\Exceptions\ApiBadParametersException; 6use Shaarli\Api\Exceptions\ApiBadParametersException;
6use Shaarli\Bookmark\BookmarkFileService; 7use Shaarli\Bookmark\BookmarkFileService;
7use Shaarli\Bookmark\LinkDB; 8use Shaarli\Bookmark\LinkDB;
@@ -64,6 +65,7 @@ class PutTagTest extends \Shaarli\TestCase
64 */ 65 */
65 protected function setUp(): void 66 protected function setUp(): void
66 { 67 {
68 $mutex = new NoMutex();
67 $this->conf = new ConfigManager('tests/utils/config/configJson'); 69 $this->conf = new ConfigManager('tests/utils/config/configJson');
68 $this->conf->set('resource.datastore', self::$testDatastore); 70 $this->conf->set('resource.datastore', self::$testDatastore);
69 $this->refDB = new \ReferenceLinkDB(); 71 $this->refDB = new \ReferenceLinkDB();
@@ -71,7 +73,7 @@ class PutTagTest extends \Shaarli\TestCase
71 $refHistory = new \ReferenceHistory(); 73 $refHistory = new \ReferenceHistory();
72 $refHistory->write(self::$testHistory); 74 $refHistory->write(self::$testHistory);
73 $this->history = new History(self::$testHistory); 75 $this->history = new History(self::$testHistory);
74 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 76 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
75 77
76 $this->container = new Container(); 78 $this->container = new Container();
77 $this->container['conf'] = $this->conf; 79 $this->container['conf'] = $this->conf;
diff --git a/tests/bookmark/BookmarkArrayTest.php b/tests/bookmark/BookmarkArrayTest.php
index ebed9bfc..1953078c 100644
--- a/tests/bookmark/BookmarkArrayTest.php
+++ b/tests/bookmark/BookmarkArrayTest.php
@@ -91,19 +91,6 @@ class BookmarkArrayTest extends TestCase
91 } 91 }
92 92
93 /** 93 /**
94 * Test adding a bad entry: invalid ID type
95 */
96 public function testArrayAccessAddBadEntryIdType()
97 {
98 $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
99
100 $array = new BookmarkArray();
101 $bookmark = (new Bookmark())->setId('nope');
102 $bookmark->validate();
103 $array[] = $bookmark;
104 }
105
106 /**
107 * Test adding a bad entry: ID/offset not consistent 94 * Test adding a bad entry: ID/offset not consistent
108 */ 95 */
109 public function testArrayAccessAddBadEntryIdOffset() 96 public function testArrayAccessAddBadEntryIdOffset()
diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php
index c399822b..f619aff3 100644
--- a/tests/bookmark/BookmarkFileServiceTest.php
+++ b/tests/bookmark/BookmarkFileServiceTest.php
@@ -6,6 +6,7 @@
6namespace Shaarli\Bookmark; 6namespace Shaarli\Bookmark;
7 7
8use DateTime; 8use DateTime;
9use malkusch\lock\mutex\NoMutex;
9use ReferenceLinkDB; 10use ReferenceLinkDB;
10use ReflectionClass; 11use ReflectionClass;
11use Shaarli; 12use Shaarli;
@@ -52,6 +53,9 @@ class BookmarkFileServiceTest extends TestCase
52 */ 53 */
53 protected $privateLinkDB = null; 54 protected $privateLinkDB = null;
54 55
56 /** @var NoMutex */
57 protected $mutex;
58
55 /** 59 /**
56 * Instantiates public and private LinkDBs with test data 60 * Instantiates public and private LinkDBs with test data
57 * 61 *
@@ -68,6 +72,8 @@ class BookmarkFileServiceTest extends TestCase
68 */ 72 */
69 protected function setUp(): void 73 protected function setUp(): void
70 { 74 {
75 $this->mutex = new NoMutex();
76
71 if (file_exists(self::$testDatastore)) { 77 if (file_exists(self::$testDatastore)) {
72 unlink(self::$testDatastore); 78 unlink(self::$testDatastore);
73 } 79 }
@@ -87,8 +93,8 @@ class BookmarkFileServiceTest extends TestCase
87 $this->refDB = new \ReferenceLinkDB(); 93 $this->refDB = new \ReferenceLinkDB();
88 $this->refDB->write(self::$testDatastore); 94 $this->refDB->write(self::$testDatastore);
89 $this->history = new History('sandbox/history.php'); 95 $this->history = new History('sandbox/history.php');
90 $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, false); 96 $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
91 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 97 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
92 } 98 }
93 99
94 /** 100 /**
@@ -105,7 +111,7 @@ class BookmarkFileServiceTest extends TestCase
105 $db = self::getMethod('migrate'); 111 $db = self::getMethod('migrate');
106 $db->invokeArgs($this->privateLinkDB, []); 112 $db->invokeArgs($this->privateLinkDB, []);
107 113
108 $db = new \FakeBookmarkService($this->conf, $this->history, true); 114 $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true);
109 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); 115 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
110 $this->assertEquals($this->refDB->countLinks(), $db->count()); 116 $this->assertEquals($this->refDB->countLinks(), $db->count());
111 } 117 }
@@ -174,7 +180,7 @@ class BookmarkFileServiceTest extends TestCase
174 $this->assertEquals($updated, $bookmark->getUpdated()); 180 $this->assertEquals($updated, $bookmark->getUpdated());
175 181
176 // reload from file 182 // reload from file
177 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 183 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
178 184
179 $bookmark = $this->privateLinkDB->get(43); 185 $bookmark = $this->privateLinkDB->get(43);
180 $this->assertEquals(43, $bookmark->getId()); 186 $this->assertEquals(43, $bookmark->getId());
@@ -212,7 +218,7 @@ class BookmarkFileServiceTest extends TestCase
212 $this->assertNull($bookmark->getUpdated()); 218 $this->assertNull($bookmark->getUpdated());
213 219
214 // reload from file 220 // reload from file
215 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 221 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
216 222
217 $bookmark = $this->privateLinkDB->get(43); 223 $bookmark = $this->privateLinkDB->get(43);
218 $this->assertEquals(43, $bookmark->getId()); 224 $this->assertEquals(43, $bookmark->getId());
@@ -242,7 +248,7 @@ class BookmarkFileServiceTest extends TestCase
242 $this->assertEquals(43, $bookmark->getId()); 248 $this->assertEquals(43, $bookmark->getId());
243 249
244 // reload from file 250 // reload from file
245 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 251 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
246 252
247 $this->privateLinkDB->get(43); 253 $this->privateLinkDB->get(43);
248 } 254 }
@@ -259,17 +265,6 @@ class BookmarkFileServiceTest extends TestCase
259 } 265 }
260 266
261 /** 267 /**
262 * Test add() method with an entry which is not a bookmark instance
263 */
264 public function testAddNotABookmark()
265 {
266 $this->expectException(\Exception::class);
267 $this->expectExceptionMessage('Provided data is invalid');
268
269 $this->privateLinkDB->add(['title' => 'hi!']);
270 }
271
272 /**
273 * Test add() method with a Bookmark already containing an ID 268 * Test add() method with a Bookmark already containing an ID
274 */ 269 */
275 public function testAddWithId() 270 public function testAddWithId()
@@ -314,7 +309,7 @@ class BookmarkFileServiceTest extends TestCase
314 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); 309 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
315 310
316 // reload from file 311 // reload from file
317 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 312 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
318 313
319 $bookmark = $this->privateLinkDB->get(42); 314 $bookmark = $this->privateLinkDB->get(42);
320 $this->assertEquals(42, $bookmark->getId()); 315 $this->assertEquals(42, $bookmark->getId());
@@ -355,7 +350,7 @@ class BookmarkFileServiceTest extends TestCase
355 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); 350 $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated());
356 351
357 // reload from file 352 // reload from file
358 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 353 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
359 354
360 $bookmark = $this->privateLinkDB->get(42); 355 $bookmark = $this->privateLinkDB->get(42);
361 $this->assertEquals(42, $bookmark->getId()); 356 $this->assertEquals(42, $bookmark->getId());
@@ -388,7 +383,7 @@ class BookmarkFileServiceTest extends TestCase
388 $this->assertEquals($title, $bookmark->getTitle()); 383 $this->assertEquals($title, $bookmark->getTitle());
389 384
390 // reload from file 385 // reload from file
391 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 386 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
392 387
393 $bookmark = $this->privateLinkDB->get(42); 388 $bookmark = $this->privateLinkDB->get(42);
394 $this->assertEquals(42, $bookmark->getId()); 389 $this->assertEquals(42, $bookmark->getId());
@@ -407,17 +402,6 @@ class BookmarkFileServiceTest extends TestCase
407 } 402 }
408 403
409 /** 404 /**
410 * Test set() method with an entry which is not a bookmark instance
411 */
412 public function testSetNotABookmark()
413 {
414 $this->expectException(\Exception::class);
415 $this->expectExceptionMessage('Provided data is invalid');
416
417 $this->privateLinkDB->set(['title' => 'hi!']);
418 }
419
420 /**
421 * Test set() method with a Bookmark without an ID defined. 405 * Test set() method with a Bookmark without an ID defined.
422 */ 406 */
423 public function testSetWithoutId() 407 public function testSetWithoutId()
@@ -452,7 +436,7 @@ class BookmarkFileServiceTest extends TestCase
452 $this->assertEquals(43, $bookmark->getId()); 436 $this->assertEquals(43, $bookmark->getId());
453 437
454 // reload from file 438 // reload from file
455 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 439 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
456 440
457 $bookmark = $this->privateLinkDB->get(43); 441 $bookmark = $this->privateLinkDB->get(43);
458 $this->assertEquals(43, $bookmark->getId()); 442 $this->assertEquals(43, $bookmark->getId());
@@ -472,7 +456,7 @@ class BookmarkFileServiceTest extends TestCase
472 $this->assertEquals($title, $bookmark->getTitle()); 456 $this->assertEquals($title, $bookmark->getTitle());
473 457
474 // reload from file 458 // reload from file
475 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 459 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
476 460
477 $bookmark = $this->privateLinkDB->get(42); 461 $bookmark = $this->privateLinkDB->get(42);
478 $this->assertEquals(42, $bookmark->getId()); 462 $this->assertEquals(42, $bookmark->getId());
@@ -491,17 +475,6 @@ class BookmarkFileServiceTest extends TestCase
491 } 475 }
492 476
493 /** 477 /**
494 * Test addOrSet() method with an entry which is not a bookmark instance
495 */
496 public function testAddOrSetNotABookmark()
497 {
498 $this->expectException(\Exception::class);
499 $this->expectExceptionMessage('Provided data is invalid');
500
501 $this->privateLinkDB->addOrSet(['title' => 'hi!']);
502 }
503
504 /**
505 * Test addOrSet() method for a bookmark without any field set and without writing the data store 478 * Test addOrSet() method for a bookmark without any field set and without writing the data store
506 */ 479 */
507 public function testAddOrSetMinimalNoWrite() 480 public function testAddOrSetMinimalNoWrite()
@@ -515,7 +488,7 @@ class BookmarkFileServiceTest extends TestCase
515 $this->assertEquals($title, $bookmark->getTitle()); 488 $this->assertEquals($title, $bookmark->getTitle());
516 489
517 // reload from file 490 // reload from file
518 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 491 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
519 492
520 $bookmark = $this->privateLinkDB->get(42); 493 $bookmark = $this->privateLinkDB->get(42);
521 $this->assertEquals(42, $bookmark->getId()); 494 $this->assertEquals(42, $bookmark->getId());
@@ -541,7 +514,7 @@ class BookmarkFileServiceTest extends TestCase
541 $this->assertInstanceOf(BookmarkNotFoundException::class, $exception); 514 $this->assertInstanceOf(BookmarkNotFoundException::class, $exception);
542 515
543 // reload from file 516 // reload from file
544 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, true); 517 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
545 518
546 $this->privateLinkDB->get(42); 519 $this->privateLinkDB->get(42);
547 } 520 }
@@ -559,17 +532,6 @@ class BookmarkFileServiceTest extends TestCase
559 } 532 }
560 533
561 /** 534 /**
562 * Test remove() method with an entry which is not a bookmark instance
563 */
564 public function testRemoveNotABookmark()
565 {
566 $this->expectException(\Exception::class);
567 $this->expectExceptionMessage('Provided data is invalid');
568
569 $this->privateLinkDB->remove(['title' => 'hi!']);
570 }
571
572 /**
573 * Test remove() method with a Bookmark with an unknown ID 535 * Test remove() method with a Bookmark with an unknown ID
574 */ 536 */
575 public function testRemoveWithUnknownId() 537 public function testRemoveWithUnknownId()
@@ -645,7 +607,7 @@ class BookmarkFileServiceTest extends TestCase
645 607
646 $conf = new ConfigManager('tests/utils/config/configJson'); 608 $conf = new ConfigManager('tests/utils/config/configJson');
647 $conf->set('resource.datastore', 'null/store.db'); 609 $conf->set('resource.datastore', 'null/store.db');
648 new BookmarkFileService($conf, $this->history, true); 610 new BookmarkFileService($conf, $this->history, $this->mutex, true);
649 } 611 }
650 612
651 /** 613 /**
@@ -655,7 +617,7 @@ class BookmarkFileServiceTest extends TestCase
655 { 617 {
656 unlink(self::$testDatastore); 618 unlink(self::$testDatastore);
657 $this->assertFileNotExists(self::$testDatastore); 619 $this->assertFileNotExists(self::$testDatastore);
658 new BookmarkFileService($this->conf, $this->history, true); 620 new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
659 $this->assertFileExists(self::$testDatastore); 621 $this->assertFileExists(self::$testDatastore);
660 622
661 // ensure the correct data has been written 623 // ensure the correct data has been written
@@ -669,7 +631,7 @@ class BookmarkFileServiceTest extends TestCase
669 { 631 {
670 unlink(self::$testDatastore); 632 unlink(self::$testDatastore);
671 $this->assertFileNotExists(self::$testDatastore); 633 $this->assertFileNotExists(self::$testDatastore);
672 $db = new \FakeBookmarkService($this->conf, $this->history, false); 634 $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false);
673 $this->assertFileNotExists(self::$testDatastore); 635 $this->assertFileNotExists(self::$testDatastore);
674 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); 636 $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks());
675 $this->assertCount(0, $db->getBookmarks()); 637 $this->assertCount(0, $db->getBookmarks());
@@ -702,13 +664,13 @@ class BookmarkFileServiceTest extends TestCase
702 */ 664 */
703 public function testSave() 665 public function testSave()
704 { 666 {
705 $testDB = new BookmarkFileService($this->conf, $this->history, true); 667 $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
706 $dbSize = $testDB->count(); 668 $dbSize = $testDB->count();
707 669
708 $bookmark = new Bookmark(); 670 $bookmark = new Bookmark();
709 $testDB->add($bookmark); 671 $testDB->add($bookmark);
710 672
711 $testDB = new BookmarkFileService($this->conf, $this->history, true); 673 $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
712 $this->assertEquals($dbSize + 1, $testDB->count()); 674 $this->assertEquals($dbSize + 1, $testDB->count());
713 } 675 }
714 676
@@ -718,28 +680,12 @@ class BookmarkFileServiceTest extends TestCase
718 public function testCountHiddenPublic() 680 public function testCountHiddenPublic()
719 { 681 {
720 $this->conf->set('privacy.hide_public_links', true); 682 $this->conf->set('privacy.hide_public_links', true);
721 $linkDB = new BookmarkFileService($this->conf, $this->history, false); 683 $linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
722 684
723 $this->assertEquals(0, $linkDB->count()); 685 $this->assertEquals(0, $linkDB->count());
724 } 686 }
725 687
726 /** 688 /**
727 * List the days for which bookmarks have been posted
728 */
729 public function testDays()
730 {
731 $this->assertEquals(
732 ['20100309', '20100310', '20121206', '20121207', '20130614', '20150310'],
733 $this->publicLinkDB->days()
734 );
735
736 $this->assertEquals(
737 ['20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'],
738 $this->privateLinkDB->days()
739 );
740 }
741
742 /**
743 * The URL corresponds to an existing entry in the DB 689 * The URL corresponds to an existing entry in the DB
744 */ 690 */
745 public function testGetKnownLinkFromURL() 691 public function testGetKnownLinkFromURL()
@@ -786,6 +732,10 @@ class BookmarkFileServiceTest extends TestCase
786 // They need to be grouped with the first case found - order by date DESC: `sTuff`. 732 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
787 'sTuff' => 2, 733 'sTuff' => 2,
788 'ut' => 1, 734 'ut' => 1,
735 'assurance' => 1,
736 'coding-style' => 1,
737 'quality' => 1,
738 'standards' => 1,
789 ], 739 ],
790 $this->publicLinkDB->bookmarksCountPerTag() 740 $this->publicLinkDB->bookmarksCountPerTag()
791 ); 741 );
@@ -814,6 +764,10 @@ class BookmarkFileServiceTest extends TestCase
814 'tag3' => 1, 764 'tag3' => 1,
815 'tag4' => 1, 765 'tag4' => 1,
816 'ut' => 1, 766 'ut' => 1,
767 'assurance' => 1,
768 'coding-style' => 1,
769 'quality' => 1,
770 'standards' => 1,
817 ], 771 ],
818 $this->privateLinkDB->bookmarksCountPerTag() 772 $this->privateLinkDB->bookmarksCountPerTag()
819 ); 773 );
@@ -928,6 +882,37 @@ class BookmarkFileServiceTest extends TestCase
928 } 882 }
929 883
930 /** 884 /**
885 * Test filterHash() on a private bookmark while logged out.
886 */
887 public function testFilterHashPrivateWhileLoggedOut()
888 {
889 $this->expectException(BookmarkNotFoundException::class);
890 $this->expectExceptionMessage('The link you are trying to reach does not exist or has been deleted');
891
892 $hash = smallHash('20141125_084734' . 6);
893
894 $this->publicLinkDB->findByHash($hash);
895 }
896
897 /**
898 * Test filterHash() with private key.
899 */
900 public function testFilterHashWithPrivateKey()
901 {
902 $hash = smallHash('20141125_084734' . 6);
903 $privateKey = 'this is usually auto generated';
904
905 $bookmark = $this->privateLinkDB->findByHash($hash);
906 $bookmark->addAdditionalContentEntry('private_key', $privateKey);
907 $this->privateLinkDB->save();
908
909 $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
910 $bookmark = $this->privateLinkDB->findByHash($hash, $privateKey);
911
912 static::assertSame(6, $bookmark->getId());
913 }
914
915 /**
931 * Test linksCountPerTag all tags without filter. 916 * Test linksCountPerTag all tags without filter.
932 * Equal occurrences should be sorted alphabetically. 917 * Equal occurrences should be sorted alphabetically.
933 */ 918 */
@@ -956,6 +941,10 @@ class BookmarkFileServiceTest extends TestCase
956 'tag4' => 1, 941 'tag4' => 1,
957 'ut' => 1, 942 'ut' => 1,
958 'w3c' => 1, 943 'w3c' => 1,
944 'assurance' => 1,
945 'coding-style' => 1,
946 'quality' => 1,
947 'standards' => 1,
959 ]; 948 ];
960 $tags = $this->privateLinkDB->bookmarksCountPerTag(); 949 $tags = $this->privateLinkDB->bookmarksCountPerTag();
961 950
@@ -1054,6 +1043,10 @@ class BookmarkFileServiceTest extends TestCase
1054 'stallman' => 1, 1043 'stallman' => 1,
1055 'ut' => 1, 1044 'ut' => 1,
1056 'w3c' => 1, 1045 'w3c' => 1,
1046 'assurance' => 1,
1047 'coding-style' => 1,
1048 'quality' => 1,
1049 'standards' => 1,
1057 ]; 1050 ];
1058 $bookmark = new Bookmark(); 1051 $bookmark = new Bookmark();
1059 $bookmark->setTags(['newTagToCount', BookmarkMarkdownFormatter::NO_MD_TAG]); 1052 $bookmark->setTags(['newTagToCount', BookmarkMarkdownFormatter::NO_MD_TAG]);
@@ -1065,33 +1058,105 @@ class BookmarkFileServiceTest extends TestCase
1065 } 1058 }
1066 1059
1067 /** 1060 /**
1068 * Test filterDay while logged in 1061 * Test find by dates in the middle of the datastore (sorted by dates) with a single bookmark as a result.
1069 */ 1062 */
1070 public function testFilterDayLoggedIn(): void 1063 public function testFilterByDateMidTimePeriodSingleBookmark(): void
1071 { 1064 {
1072 $bookmarks = $this->privateLinkDB->filterDay('20121206'); 1065 $bookmarks = $this->privateLinkDB->findByDate(
1073 $expectedIds = [4, 9, 1, 0]; 1066 DateTime::createFromFormat('Ymd_His', '20121206_150000'),
1067 DateTime::createFromFormat('Ymd_His', '20121206_160000'),
1068 $before,
1069 $after
1070 );
1074 1071
1075 static::assertCount(4, $bookmarks); 1072 static::assertCount(1, $bookmarks);
1076 foreach ($bookmarks as $bookmark) { 1073
1077 $i = ($i ?? -1) + 1; 1074 static::assertSame(9, $bookmarks[0]->getId());
1078 static::assertSame($expectedIds[$i], $bookmark->getId()); 1075 static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $before);
1079 } 1076 static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_172539'), $after);
1080 } 1077 }
1081 1078
1082 /** 1079 /**
1083 * Test filterDay while logged out 1080 * Test find by dates in the middle of the datastore (sorted by dates) with a multiple bookmarks as a result.
1084 */ 1081 */
1085 public function testFilterDayLoggedOut(): void 1082 public function testFilterByDateMidTimePeriodMultipleBookmarks(): void
1086 { 1083 {
1087 $bookmarks = $this->publicLinkDB->filterDay('20121206'); 1084 $bookmarks = $this->privateLinkDB->findByDate(
1088 $expectedIds = [4, 9, 1]; 1085 DateTime::createFromFormat('Ymd_His', '20121206_150000'),
1086 DateTime::createFromFormat('Ymd_His', '20121206_180000'),
1087 $before,
1088 $after
1089 );
1089 1090
1090 static::assertCount(3, $bookmarks); 1091 static::assertCount(2, $bookmarks);
1091 foreach ($bookmarks as $bookmark) { 1092
1092 $i = ($i ?? -1) + 1; 1093 static::assertSame(1, $bookmarks[0]->getId());
1093 static::assertSame($expectedIds[$i], $bookmark->getId()); 1094 static::assertSame(9, $bookmarks[1]->getId());
1094 } 1095 static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_142300'), $before);
1096 static::assertEquals(DateTime::createFromFormat('Ymd_His', '20121206_182539'), $after);
1097 }
1098
1099 /**
1100 * Test find by dates at the end of the datastore (sorted by dates).
1101 */
1102 public function testFilterByDateLastTimePeriod(): void
1103 {
1104 $after = new DateTime();
1105 $bookmarks = $this->privateLinkDB->findByDate(
1106 DateTime::createFromFormat('Ymd_His', '20150310_114640'),
1107 DateTime::createFromFormat('Ymd_His', '20450101_010101'),
1108 $before,
1109 $after
1110 );
1111
1112 static::assertCount(1, $bookmarks);
1113
1114 static::assertSame(41, $bookmarks[0]->getId());
1115 static::assertEquals(DateTime::createFromFormat('Ymd_His', '20150310_114633'), $before);
1116 static::assertNull($after);
1117 }
1118
1119 /**
1120 * Test find by dates at the beginning of the datastore (sorted by dates).
1121 */
1122 public function testFilterByDateFirstTimePeriod(): void
1123 {
1124 $before = new DateTime();
1125 $bookmarks = $this->privateLinkDB->findByDate(
1126 DateTime::createFromFormat('Ymd_His', '20000101_101010'),
1127 DateTime::createFromFormat('Ymd_His', '20100309_110000'),
1128 $before,
1129 $after
1130 );
1131
1132 static::assertCount(1, $bookmarks);
1133
1134 static::assertSame(11, $bookmarks[0]->getId());
1135 static::assertNull($before);
1136 static::assertEquals(DateTime::createFromFormat('Ymd_His', '20100310_101010'), $after);
1137 }
1138
1139 /**
1140 * Test getLatest with a sticky bookmark: it should be ignored and return the latest by creation date instead.
1141 */
1142 public function testGetLatestWithSticky(): void
1143 {
1144 $bookmark = $this->publicLinkDB->getLatest();
1145
1146 static::assertSame(41, $bookmark->getId());
1147 }
1148
1149 /**
1150 * Test getLatest with a sticky bookmark: it should be ignored and return the latest by creation date instead.
1151 */
1152 public function testGetLatestEmptyDatastore(): void
1153 {
1154 unlink($this->conf->get('resource.datastore'));
1155 $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false);
1156
1157 $bookmark = $this->publicLinkDB->getLatest();
1158
1159 static::assertNull($bookmark);
1095 } 1160 }
1096 1161
1097 /** 1162 /**
diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php
index 48c7f824..835674f2 100644
--- a/tests/bookmark/BookmarkFilterTest.php
+++ b/tests/bookmark/BookmarkFilterTest.php
@@ -2,7 +2,7 @@
2 2
3namespace Shaarli\Bookmark; 3namespace Shaarli\Bookmark;
4 4
5use Exception; 5use malkusch\lock\mutex\NoMutex;
6use ReferenceLinkDB; 6use ReferenceLinkDB;
7use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
8use Shaarli\History; 8use Shaarli\History;
@@ -37,13 +37,14 @@ class BookmarkFilterTest extends TestCase
37 */ 37 */
38 public static function setUpBeforeClass(): void 38 public static function setUpBeforeClass(): void
39 { 39 {
40 $mutex = new NoMutex();
40 $conf = new ConfigManager('tests/utils/config/configJson'); 41 $conf = new ConfigManager('tests/utils/config/configJson');
41 $conf->set('resource.datastore', self::$testDatastore); 42 $conf->set('resource.datastore', self::$testDatastore);
42 self::$refDB = new \ReferenceLinkDB(); 43 self::$refDB = new \ReferenceLinkDB();
43 self::$refDB->write(self::$testDatastore); 44 self::$refDB->write(self::$testDatastore);
44 $history = new History('sandbox/history.php'); 45 $history = new History('sandbox/history.php');
45 self::$bookmarkService = new \FakeBookmarkService($conf, $history, true); 46 self::$bookmarkService = new \FakeBookmarkService($conf, $history, $mutex, true);
46 self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks()); 47 self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf);
47 } 48 }
48 49
49 /** 50 /**
@@ -523,4 +524,43 @@ class BookmarkFilterTest extends TestCase
523 )) 524 ))
524 ); 525 );
525 } 526 }
527
528 /**
529 * Test search result highlights in every field of bookmark reference #9.
530 */
531 public function testFullTextSearchHighlight(): void
532 {
533 $bookmarks = self::$linkFilter->filter(
534 BookmarkFilter::$FILTER_TEXT,
535 '"psr-2" coding guide http fig "psr-2/" "This guide" basic standard. coding-style quality assurance'
536 );
537
538 static::assertCount(1, $bookmarks);
539 static::assertArrayHasKey(9, $bookmarks);
540
541 $bookmark = $bookmarks[9];
542 $expectedHighlights = [
543 'title' => [
544 ['start' => 0, 'end' => 5], // "psr-2"
545 ['start' => 7, 'end' => 13], // coding
546 ['start' => 20, 'end' => 25], // guide
547 ],
548 'description' => [
549 ['start' => 0, 'end' => 10], // "This guide"
550 ['start' => 45, 'end' => 50], // basic
551 ['start' => 58, 'end' => 67], // standard.
552 ],
553 'url' => [
554 ['start' => 0, 'end' => 4], // http
555 ['start' => 15, 'end' => 18], // fig
556 ['start' => 27, 'end' => 33], // "psr-2/"
557 ],
558 'tags' => [
559 ['start' => 0, 'end' => 12], // coding-style
560 ['start' => 23, 'end' => 30], // quality
561 ['start' => 31, 'end' => 40], // assurance
562 ],
563 ];
564 static::assertSame($expectedHighlights, $bookmark->getAdditionalContentEntry('search_highlight'));
565 }
526} 566}
diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php
index 25704004..0c8420ce 100644
--- a/tests/bookmark/BookmarkInitializerTest.php
+++ b/tests/bookmark/BookmarkInitializerTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Bookmark; 3namespace Shaarli\Bookmark;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Config\ConfigManager; 6use Shaarli\Config\ConfigManager;
6use Shaarli\History; 7use Shaarli\History;
7use Shaarli\TestCase; 8use Shaarli\TestCase;
@@ -34,11 +35,15 @@ class BookmarkInitializerTest extends TestCase
34 /** @var BookmarkInitializer instance */ 35 /** @var BookmarkInitializer instance */
35 protected $initializer; 36 protected $initializer;
36 37
38 /** @var NoMutex */
39 protected $mutex;
40
37 /** 41 /**
38 * Initialize an empty BookmarkFileService 42 * Initialize an empty BookmarkFileService
39 */ 43 */
40 public function setUp(): void 44 public function setUp(): void
41 { 45 {
46 $this->mutex = new NoMutex();
42 if (file_exists(self::$testDatastore)) { 47 if (file_exists(self::$testDatastore)) {
43 unlink(self::$testDatastore); 48 unlink(self::$testDatastore);
44 } 49 }
@@ -47,7 +52,7 @@ class BookmarkInitializerTest extends TestCase
47 $this->conf = new ConfigManager(self::$testConf); 52 $this->conf = new ConfigManager(self::$testConf);
48 $this->conf->set('resource.datastore', self::$testDatastore); 53 $this->conf->set('resource.datastore', self::$testDatastore);
49 $this->history = new History('sandbox/history.php'); 54 $this->history = new History('sandbox/history.php');
50 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 55 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
51 56
52 $this->initializer = new BookmarkInitializer($this->bookmarkService); 57 $this->initializer = new BookmarkInitializer($this->bookmarkService);
53 } 58 }
@@ -59,7 +64,7 @@ class BookmarkInitializerTest extends TestCase
59 { 64 {
60 $refDB = new \ReferenceLinkDB(); 65 $refDB = new \ReferenceLinkDB();
61 $refDB->write(self::$testDatastore); 66 $refDB->write(self::$testDatastore);
62 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 67 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
63 $this->initializer = new BookmarkInitializer($this->bookmarkService); 68 $this->initializer = new BookmarkInitializer($this->bookmarkService);
64 69
65 $this->initializer->initialize(); 70 $this->initializer->initialize();
@@ -90,7 +95,7 @@ class BookmarkInitializerTest extends TestCase
90 $this->bookmarkService->save(); 95 $this->bookmarkService->save();
91 96
92 // Reload from file 97 // Reload from file
93 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 98 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
94 $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count()); 99 $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
95 100
96 $bookmark = $this->bookmarkService->get(43); 101 $bookmark = $this->bookmarkService->get(43);
@@ -121,7 +126,7 @@ class BookmarkInitializerTest extends TestCase
121 public function testInitializeNonExistentDataStore(): void 126 public function testInitializeNonExistentDataStore(): void
122 { 127 {
123 $this->conf->set('resource.datastore', static::$testDatastore . '_empty'); 128 $this->conf->set('resource.datastore', static::$testDatastore . '_empty');
124 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 129 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true);
125 130
126 $this->initializer->initialize(); 131 $this->initializer->initialize();
127 132
diff --git a/tests/bookmark/BookmarkTest.php b/tests/bookmark/BookmarkTest.php
index afec2440..cb91b26b 100644
--- a/tests/bookmark/BookmarkTest.php
+++ b/tests/bookmark/BookmarkTest.php
@@ -79,6 +79,23 @@ class BookmarkTest extends TestCase
79 } 79 }
80 80
81 /** 81 /**
82 * Test fromArray() with a link with a custom tags separator
83 */
84 public function testFromArrayCustomTagsSeparator()
85 {
86 $data = [
87 'id' => 1,
88 'tags' => ['tag1', 'tag2', 'chair'],
89 ];
90
91 $bookmark = (new Bookmark())->fromArray($data, '@');
92 $this->assertEquals($data['id'], $bookmark->getId());
93 $this->assertEquals($data['tags'], $bookmark->getTags());
94 $this->assertEquals('tag1@tag2@chair', $bookmark->getTagsString('@'));
95 }
96
97
98 /**
82 * Test validate() with a valid minimal bookmark 99 * Test validate() with a valid minimal bookmark
83 */ 100 */
84 public function testValidateValidFullBookmark() 101 public function testValidateValidFullBookmark()
@@ -154,25 +171,6 @@ class BookmarkTest extends TestCase
154 } 171 }
155 172
156 /** 173 /**
157 * Test validate() with a a bookmark with a non integer ID.
158 */
159 public function testValidateNotValidStringId()
160 {
161 $bookmark = new Bookmark();
162 $bookmark->setId('str');
163 $bookmark->setShortUrl('abc');
164 $bookmark->setCreated(\DateTime::createFromFormat('Ymd_His', '20190514_200102'));
165 $exception = null;
166 try {
167 $bookmark->validate();
168 } catch (InvalidBookmarkException $e) {
169 $exception = $e;
170 }
171 $this->assertNotNull($exception);
172 $this->assertContainsPolyfill('- ID: str'. PHP_EOL, $exception->getMessage());
173 }
174
175 /**
176 * Test validate() with a a bookmark without short url. 174 * Test validate() with a a bookmark without short url.
177 */ 175 */
178 public function testValidateNotValidNoShortUrl() 176 public function testValidateNotValidNoShortUrl()
@@ -211,25 +209,6 @@ class BookmarkTest extends TestCase
211 } 209 }
212 210
213 /** 211 /**
214 * Test validate() with a a bookmark with a bad created datetime.
215 */
216 public function testValidateNotValidBadCreated()
217 {
218 $bookmark = new Bookmark();
219 $bookmark->setId(1);
220 $bookmark->setShortUrl('abc');
221 $bookmark->setCreated('hi!');
222 $exception = null;
223 try {
224 $bookmark->validate();
225 } catch (InvalidBookmarkException $e) {
226 $exception = $e;
227 }
228 $this->assertNotNull($exception);
229 $this->assertContainsPolyfill('- Created: Not a DateTime object'. PHP_EOL, $exception->getMessage());
230 }
231
232 /**
233 * Test setId() and make sure that default fields are generated. 212 * Test setId() and make sure that default fields are generated.
234 */ 213 */
235 public function testSetIdEmptyGeneratedFields() 214 public function testSetIdEmptyGeneratedFields()
@@ -290,7 +269,7 @@ class BookmarkTest extends TestCase
290 { 269 {
291 $bookmark = new Bookmark(); 270 $bookmark = new Bookmark();
292 271
293 $str = 'tag1 tag2 tag3.tag3-2, tag4 , -tag5 '; 272 $str = 'tag1 tag2 tag3.tag3-2 tag4 -tag5 ';
294 $bookmark->setTagsString($str); 273 $bookmark->setTagsString($str);
295 $this->assertEquals( 274 $this->assertEquals(
296 [ 275 [
@@ -314,9 +293,9 @@ class BookmarkTest extends TestCase
314 $array = [ 293 $array = [
315 'tag1 ', 294 'tag1 ',
316 ' tag2', 295 ' tag2',
317 'tag3.tag3-2,', 296 'tag3.tag3-2',
318 ', tag4', 297 ' tag4',
319 ', ', 298 ' ',
320 '-tag5 ', 299 '-tag5 ',
321 ]; 300 ];
322 $bookmark->setTags($array); 301 $bookmark->setTags($array);
@@ -385,4 +364,48 @@ class BookmarkTest extends TestCase
385 $bookmark->deleteTag('nope'); 364 $bookmark->deleteTag('nope');
386 $this->assertEquals(['tag1', 'tag2', 'chair'], $bookmark->getTags()); 365 $this->assertEquals(['tag1', 'tag2', 'chair'], $bookmark->getTags());
387 } 366 }
367
368 /**
369 * Test shouldUpdateThumbnail() with bookmarks needing an update.
370 */
371 public function testShouldUpdateThumbnail(): void
372 {
373 $bookmark = (new Bookmark())->setUrl('http://domain.tld/with-image');
374
375 static::assertTrue($bookmark->shouldUpdateThumbnail());
376
377 $bookmark = (new Bookmark())
378 ->setUrl('http://domain.tld/with-image')
379 ->setThumbnail('unknown file')
380 ;
381
382 static::assertTrue($bookmark->shouldUpdateThumbnail());
383 }
384
385 /**
386 * Test shouldUpdateThumbnail() with bookmarks that should not update.
387 */
388 public function testShouldNotUpdateThumbnail(): void
389 {
390 $bookmark = (new Bookmark());
391
392 static::assertFalse($bookmark->shouldUpdateThumbnail());
393
394 $bookmark = (new Bookmark())
395 ->setUrl('ftp://domain.tld/other-protocol', ['ftp'])
396 ;
397
398 static::assertFalse($bookmark->shouldUpdateThumbnail());
399
400 $bookmark = (new Bookmark())
401 ->setUrl('http://domain.tld/with-image')
402 ->setThumbnail(__FILE__)
403 ;
404
405 static::assertFalse($bookmark->shouldUpdateThumbnail());
406
407 $bookmark = (new Bookmark())->setUrl('/shaare/abcdef');
408
409 static::assertFalse($bookmark->shouldUpdateThumbnail());
410 }
388} 411}
diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php
index ef00b92f..ddab4e3c 100644
--- a/tests/bookmark/LinkUtilsTest.php
+++ b/tests/bookmark/LinkUtilsTest.php
@@ -94,8 +94,108 @@ class LinkUtilsTest extends TestCase
94 public function testHtmlExtractExistentNameTag() 94 public function testHtmlExtractExistentNameTag()
95 { 95 {
96 $description = 'Bob and Alice share cookies.'; 96 $description = 'Bob and Alice share cookies.';
97
98 // Simple one line
97 $html = '<html><meta>stuff2</meta><meta name="description" content="' . $description . '"/></html>'; 99 $html = '<html><meta>stuff2</meta><meta name="description" content="' . $description . '"/></html>';
98 $this->assertEquals($description, html_extract_tag('description', $html)); 100 $this->assertEquals($description, html_extract_tag('description', $html));
101
102 // Simple OpenGraph
103 $html = '<meta property="og:description" content="' . $description . '">';
104 $this->assertEquals($description, html_extract_tag('description', $html));
105
106 // Simple reversed OpenGraph
107 $html = '<meta content="' . $description . '" property="og:description">';
108 $this->assertEquals($description, html_extract_tag('description', $html));
109
110 // ItemProp OpenGraph
111 $html = '<meta itemprop="og:description" content="' . $description . '">';
112 $this->assertEquals($description, html_extract_tag('description', $html));
113
114 // OpenGraph without quotes
115 $html = '<meta property=og:description content="' . $description . '">';
116 $this->assertEquals($description, html_extract_tag('description', $html));
117
118 // OpenGraph reversed without quotes
119 $html = '<meta content="' . $description . '" property=og:description>';
120 $this->assertEquals($description, html_extract_tag('description', $html));
121
122 // OpenGraph with noise
123 $html = '<meta tag1="content1" property="og:description" tag2="content2" content="' .
124 $description . '" tag3="content3">';
125 $this->assertEquals($description, html_extract_tag('description', $html));
126
127 // OpenGraph reversed with noise
128 $html = '<meta tag1="content1" content="' . $description . '" ' .
129 'tag3="content3" tag2="content2" property="og:description">';
130 $this->assertEquals($description, html_extract_tag('description', $html));
131
132 // OpenGraph multiple properties start
133 $html = '<meta property="unrelated og:description" content="' . $description . '">';
134 $this->assertEquals($description, html_extract_tag('description', $html));
135
136 // OpenGraph multiple properties end
137 $html = '<meta property="og:description unrelated" content="' . $description . '">';
138 $this->assertEquals($description, html_extract_tag('description', $html));
139
140 // OpenGraph multiple properties both end
141 $html = '<meta property="og:unrelated1 og:description og:unrelated2" content="' . $description . '">';
142 $this->assertEquals($description, html_extract_tag('description', $html));
143
144 // OpenGraph multiple properties both end with noise
145 $html = '<meta tag1="content1" property="og:unrelated1 og:description og:unrelated2" '.
146 'tag2="content2" content="' . $description . '" tag3="content3">';
147 $this->assertEquals($description, html_extract_tag('description', $html));
148
149 // OpenGraph reversed multiple properties start
150 $html = '<meta content="' . $description . '" property="unrelated og:description">';
151 $this->assertEquals($description, html_extract_tag('description', $html));
152
153 // OpenGraph reversed multiple properties end
154 $html = '<meta content="' . $description . '" property="og:description unrelated">';
155 $this->assertEquals($description, html_extract_tag('description', $html));
156
157 // OpenGraph reversed multiple properties both end
158 $html = '<meta content="' . $description . '" property="og:unrelated1 og:description og:unrelated2">';
159 $this->assertEquals($description, html_extract_tag('description', $html));
160
161 // OpenGraph reversed multiple properties both end with noise
162 $html = '<meta tag1="content1" content="' . $description . '" tag2="content2" '.
163 'property="og:unrelated1 og:description og:unrelated2" tag3="content3">';
164 $this->assertEquals($description, html_extract_tag('description', $html));
165
166 // Suggestion from #1375
167 $html = '<meta property="og:description" name="description" content="' . $description . '">';
168 $this->assertEquals($description, html_extract_tag('description', $html));
169 }
170
171 /**
172 * Test html_extract_tag() with double quoted content containing single quote, and the opposite.
173 */
174 public function testHtmlExtractExistentNameTagWithMixedQuotes(): void
175 {
176 $description = 'Bob and Alice share M&M\'s.';
177
178 $html = '<meta property="og:description" content="' . $description . '">';
179 $this->assertEquals($description, html_extract_tag('description', $html));
180
181 $html = '<meta tag1="content1" property="og:unrelated1 og:description og:unrelated2" '.
182 'tag2="content2" content="' . $description . '" tag3="content3">';
183 $this->assertEquals($description, html_extract_tag('description', $html));
184
185 $html = '<meta property="og:description" name="description" content="' . $description . '">';
186 $this->assertEquals($description, html_extract_tag('description', $html));
187
188 $description = 'Bob and Alice share "cookies".';
189
190 $html = '<meta property="og:description" content=\'' . $description . '\'>';
191 $this->assertEquals($description, html_extract_tag('description', $html));
192
193 $html = '<meta tag1="content1" property="og:unrelated1 og:description og:unrelated2" '.
194 'tag2="content2" content=\'' . $description . '\' tag3="content3">';
195 $this->assertEquals($description, html_extract_tag('description', $html));
196
197 $html = '<meta property="og:description" name="description" content=\'' . $description . '\'>';
198 $this->assertEquals($description, html_extract_tag('description', $html));
99 } 199 }
100 200
101 /** 201 /**
@@ -105,6 +205,25 @@ class LinkUtilsTest extends TestCase
105 { 205 {
106 $html = '<html><meta>stuff2</meta><meta name="image" content="img"/></html>'; 206 $html = '<html><meta>stuff2</meta><meta name="image" content="img"/></html>';
107 $this->assertFalse(html_extract_tag('description', $html)); 207 $this->assertFalse(html_extract_tag('description', $html));
208
209 // Partial meta tag
210 $html = '<meta content="Brief description">';
211 $this->assertFalse(html_extract_tag('description', $html));
212
213 $html = '<meta property="og:description">';
214 $this->assertFalse(html_extract_tag('description', $html));
215
216 $html = '<meta tag1="content1" property="og:description">';
217 $this->assertFalse(html_extract_tag('description', $html));
218
219 $html = '<meta property="og:description" tag1="content1">';
220 $this->assertFalse(html_extract_tag('description', $html));
221
222 $html = '<meta tag1="content1" content="Brief description">';
223 $this->assertFalse(html_extract_tag('description', $html));
224
225 $html = '<meta content="Brief description" tag1="content1">';
226 $this->assertFalse(html_extract_tag('description', $html));
108 } 227 }
109 228
110 /** 229 /**
@@ -127,60 +246,93 @@ class LinkUtilsTest extends TestCase
127 } 246 }
128 247
129 /** 248 /**
249 * Test the header callback with valid value
250 */
251 public function testCurlHeaderCallbackOk(): void
252 {
253 $callback = get_curl_header_callback($charset, 'ut_curl_getinfo_ok');
254 $data = [
255 'HTTP/1.1 200 OK',
256 'Server: GitHub.com',
257 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
258 'Content-Type: text/html; charset=utf-8',
259 'Status: 200 OK',
260 ];
261
262 foreach ($data as $chunk) {
263 static::assertIsInt($callback(null, $chunk));
264 }
265
266 static::assertSame('utf-8', $charset);
267 }
268
269 /**
130 * Test the download callback with valid value 270 * Test the download callback with valid value
131 */ 271 */
132 public function testCurlDownloadCallbackOk() 272 public function testCurlDownloadCallbackOk(): void
133 { 273 {
274 $charset = 'utf-8';
134 $callback = get_curl_download_callback( 275 $callback = get_curl_download_callback(
135 $charset, 276 $charset,
136 $title, 277 $title,
137 $desc, 278 $desc,
138 $keywords, 279 $keywords,
139 false, 280 false,
140 'ut_curl_getinfo_ok' 281 ' '
141 ); 282 );
283
142 $data = [ 284 $data = [
143 'HTTP/1.1 200 OK', 285 'th=device-width">'
144 'Server: GitHub.com',
145 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
146 'Content-Type: text/html; charset=utf-8',
147 'Status: 200 OK',
148 'end' => 'th=device-width">'
149 . '<title>Refactoring · GitHub</title>' 286 . '<title>Refactoring · GitHub</title>'
150 . '<link rel="search" type="application/opensea', 287 . '<link rel="search" type="application/opensea',
151 '<title>ignored</title>' 288 '<title>ignored</title>'
152 . '<meta name="description" content="desc" />' 289 . '<meta name="description" content="desc" />'
153 . '<meta name="keywords" content="key1,key2" />', 290 . '<meta name="keywords" content="key1,key2" />',
154 ]; 291 ];
155 foreach ($data as $key => $line) { 292
156 $ignore = null; 293 foreach ($data as $chunk) {
157 $expected = $key !== 'end' ? strlen($line) : false; 294 static::assertSame(strlen($chunk), $callback(null, $chunk));
158 $this->assertEquals($expected, $callback($ignore, $line));
159 if ($expected === false) {
160 break;
161 }
162 } 295 }
163 $this->assertEquals('utf-8', $charset); 296
164 $this->assertEquals('Refactoring · GitHub', $title); 297 static::assertSame('utf-8', $charset);
165 $this->assertEmpty($desc); 298 static::assertSame('Refactoring · GitHub', $title);
166 $this->assertEmpty($keywords); 299 static::assertEmpty($desc);
300 static::assertEmpty($keywords);
301 }
302
303 /**
304 * Test the header callback with valid value
305 */
306 public function testCurlHeaderCallbackNoCharset(): void
307 {
308 $callback = get_curl_header_callback($charset, 'ut_curl_getinfo_no_charset');
309 $data = [
310 'HTTP/1.1 200 OK',
311 ];
312
313 foreach ($data as $chunk) {
314 static::assertSame(strlen($chunk), $callback(null, $chunk));
315 }
316
317 static::assertFalse($charset);
167 } 318 }
168 319
169 /** 320 /**
170 * Test the download callback with valid values and no charset 321 * Test the download callback with valid values and no charset
171 */ 322 */
172 public function testCurlDownloadCallbackOkNoCharset() 323 public function testCurlDownloadCallbackOkNoCharset(): void
173 { 324 {
325 $charset = null;
174 $callback = get_curl_download_callback( 326 $callback = get_curl_download_callback(
175 $charset, 327 $charset,
176 $title, 328 $title,
177 $desc, 329 $desc,
178 $keywords, 330 $keywords,
179 false, 331 false,
180 'ut_curl_getinfo_no_charset' 332 ' '
181 ); 333 );
334
182 $data = [ 335 $data = [
183 'HTTP/1.1 200 OK',
184 'end' => 'th=device-width">' 336 'end' => 'th=device-width">'
185 . '<title>Refactoring · GitHub</title>' 337 . '<title>Refactoring · GitHub</title>'
186 . '<link rel="search" type="application/opensea', 338 . '<link rel="search" type="application/opensea',
@@ -188,10 +340,11 @@ class LinkUtilsTest extends TestCase
188 . '<meta name="description" content="desc" />' 340 . '<meta name="description" content="desc" />'
189 . '<meta name="keywords" content="key1,key2" />', 341 . '<meta name="keywords" content="key1,key2" />',
190 ]; 342 ];
191 foreach ($data as $key => $line) { 343
192 $ignore = null; 344 foreach ($data as $chunk) {
193 $this->assertEquals(strlen($line), $callback($ignore, $line)); 345 static::assertSame(strlen($chunk), $callback(null, $chunk));
194 } 346 }
347
195 $this->assertEmpty($charset); 348 $this->assertEmpty($charset);
196 $this->assertEquals('Refactoring · GitHub', $title); 349 $this->assertEquals('Refactoring · GitHub', $title);
197 $this->assertEmpty($desc); 350 $this->assertEmpty($desc);
@@ -201,18 +354,19 @@ class LinkUtilsTest extends TestCase
201 /** 354 /**
202 * Test the download callback with valid values and no charset 355 * Test the download callback with valid values and no charset
203 */ 356 */
204 public function testCurlDownloadCallbackOkHtmlCharset() 357 public function testCurlDownloadCallbackOkHtmlCharset(): void
205 { 358 {
359 $charset = null;
206 $callback = get_curl_download_callback( 360 $callback = get_curl_download_callback(
207 $charset, 361 $charset,
208 $title, 362 $title,
209 $desc, 363 $desc,
210 $keywords, 364 $keywords,
211 false, 365 false,
212 'ut_curl_getinfo_no_charset' 366 ' '
213 ); 367 );
368
214 $data = [ 369 $data = [
215 'HTTP/1.1 200 OK',
216 '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />', 370 '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
217 'end' => 'th=device-width">' 371 'end' => 'th=device-width">'
218 . '<title>Refactoring · GitHub</title>' 372 . '<title>Refactoring · GitHub</title>'
@@ -221,14 +375,10 @@ class LinkUtilsTest extends TestCase
221 . '<meta name="description" content="desc" />' 375 . '<meta name="description" content="desc" />'
222 . '<meta name="keywords" content="key1,key2" />', 376 . '<meta name="keywords" content="key1,key2" />',
223 ]; 377 ];
224 foreach ($data as $key => $line) { 378 foreach ($data as $chunk) {
225 $ignore = null; 379 static::assertSame(strlen($chunk), $callback(null, $chunk));
226 $expected = $key !== 'end' ? strlen($line) : false;
227 $this->assertEquals($expected, $callback($ignore, $line));
228 if ($expected === false) {
229 break;
230 }
231 } 380 }
381
232 $this->assertEquals('utf-8', $charset); 382 $this->assertEquals('utf-8', $charset);
233 $this->assertEquals('Refactoring · GitHub', $title); 383 $this->assertEquals('Refactoring · GitHub', $title);
234 $this->assertEmpty($desc); 384 $this->assertEmpty($desc);
@@ -238,25 +388,27 @@ class LinkUtilsTest extends TestCase
238 /** 388 /**
239 * Test the download callback with valid values and no title 389 * Test the download callback with valid values and no title
240 */ 390 */
241 public function testCurlDownloadCallbackOkNoTitle() 391 public function testCurlDownloadCallbackOkNoTitle(): void
242 { 392 {
393 $charset = 'utf-8';
243 $callback = get_curl_download_callback( 394 $callback = get_curl_download_callback(
244 $charset, 395 $charset,
245 $title, 396 $title,
246 $desc, 397 $desc,
247 $keywords, 398 $keywords,
248 false, 399 false,
249 'ut_curl_getinfo_ok' 400 ' '
250 ); 401 );
402
251 $data = [ 403 $data = [
252 'HTTP/1.1 200 OK',
253 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea', 404 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
254 'ignored', 405 'ignored',
255 ]; 406 ];
256 foreach ($data as $key => $line) { 407
257 $ignore = null; 408 foreach ($data as $chunk) {
258 $this->assertEquals(strlen($line), $callback($ignore, $line)); 409 static::assertSame(strlen($chunk), $callback(null, $chunk));
259 } 410 }
411
260 $this->assertEquals('utf-8', $charset); 412 $this->assertEquals('utf-8', $charset);
261 $this->assertEmpty($title); 413 $this->assertEmpty($title);
262 $this->assertEmpty($desc); 414 $this->assertEmpty($desc);
@@ -264,81 +416,56 @@ class LinkUtilsTest extends TestCase
264 } 416 }
265 417
266 /** 418 /**
267 * Test the download callback with an invalid content type. 419 * Test the header callback with an invalid content type.
268 */ 420 */
269 public function testCurlDownloadCallbackInvalidContentType() 421 public function testCurlHeaderCallbackInvalidContentType(): void
270 { 422 {
271 $callback = get_curl_download_callback( 423 $callback = get_curl_header_callback($charset, 'ut_curl_getinfo_ct_ko');
272 $charset, 424 $data = [
273 $title, 425 'HTTP/1.1 200 OK',
274 $desc, 426 ];
275 $keywords, 427
276 false, 428 static::assertFalse($callback(null, $data[0]));
277 'ut_curl_getinfo_ct_ko' 429 static::assertNull($charset);
278 );
279 $ignore = null;
280 $this->assertFalse($callback($ignore, ''));
281 $this->assertEmpty($charset);
282 $this->assertEmpty($title);
283 } 430 }
284 431
285 /** 432 /**
286 * Test the download callback with an invalid response code. 433 * Test the header callback with an invalid response code.
287 */ 434 */
288 public function testCurlDownloadCallbackInvalidResponseCode() 435 public function testCurlHeaderCallbackInvalidResponseCode(): void
289 { 436 {
290 $callback = $callback = get_curl_download_callback( 437 $callback = get_curl_header_callback($charset, 'ut_curl_getinfo_rc_ko');
291 $charset, 438
292 $title, 439 static::assertFalse($callback(null, ''));
293 $desc, 440 static::assertNull($charset);
294 $keywords,
295 false,
296 'ut_curl_getinfo_rc_ko'
297 );
298 $ignore = null;
299 $this->assertFalse($callback($ignore, ''));
300 $this->assertEmpty($charset);
301 $this->assertEmpty($title);
302 } 441 }
303 442
304 /** 443 /**
305 * Test the download callback with an invalid content type and response code. 444 * Test the header callback with an invalid content type and response code.
306 */ 445 */
307 public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode() 446 public function testCurlHeaderCallbackInvalidContentTypeAndResponseCode(): void
308 { 447 {
309 $callback = $callback = get_curl_download_callback( 448 $callback = get_curl_header_callback($charset, 'ut_curl_getinfo_rs_ct_ko');
310 $charset, 449
311 $title, 450 static::assertFalse($callback(null, ''));
312 $desc, 451 static::assertNull($charset);
313 $keywords,
314 false,
315 'ut_curl_getinfo_rs_ct_ko'
316 );
317 $ignore = null;
318 $this->assertFalse($callback($ignore, ''));
319 $this->assertEmpty($charset);
320 $this->assertEmpty($title);
321 } 452 }
322 453
323 /** 454 /**
324 * Test the download callback with valid value, and retrieve_description option enabled. 455 * Test the download callback with valid value, and retrieve_description option enabled.
325 */ 456 */
326 public function testCurlDownloadCallbackOkWithDesc() 457 public function testCurlDownloadCallbackOkWithDesc(): void
327 { 458 {
459 $charset = 'utf-8';
328 $callback = get_curl_download_callback( 460 $callback = get_curl_download_callback(
329 $charset, 461 $charset,
330 $title, 462 $title,
331 $desc, 463 $desc,
332 $keywords, 464 $keywords,
333 true, 465 true,
334 'ut_curl_getinfo_ok' 466 ' '
335 ); 467 );
336 $data = [ 468 $data = [
337 'HTTP/1.1 200 OK',
338 'Server: GitHub.com',
339 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
340 'Content-Type: text/html; charset=utf-8',
341 'Status: 200 OK',
342 'th=device-width">' 469 'th=device-width">'
343 . '<title>Refactoring · GitHub</title>' 470 . '<title>Refactoring · GitHub</title>'
344 . '<link rel="search" type="application/opensea', 471 . '<link rel="search" type="application/opensea',
@@ -346,14 +473,11 @@ class LinkUtilsTest extends TestCase
346 . '<meta name="description" content="link desc" />' 473 . '<meta name="description" content="link desc" />'
347 . '<meta name="keywords" content="key1,key2" />', 474 . '<meta name="keywords" content="key1,key2" />',
348 ]; 475 ];
349 foreach ($data as $key => $line) { 476
350 $ignore = null; 477 foreach ($data as $chunk) {
351 $expected = $key !== 'end' ? strlen($line) : false; 478 static::assertSame(strlen($chunk), $callback(null, $chunk));
352 $this->assertEquals($expected, $callback($ignore, $line));
353 if ($expected === false) {
354 break;
355 }
356 } 479 }
480
357 $this->assertEquals('utf-8', $charset); 481 $this->assertEquals('utf-8', $charset);
358 $this->assertEquals('Refactoring · GitHub', $title); 482 $this->assertEquals('Refactoring · GitHub', $title);
359 $this->assertEquals('link desc', $desc); 483 $this->assertEquals('link desc', $desc);
@@ -364,8 +488,9 @@ class LinkUtilsTest extends TestCase
364 * Test the download callback with valid value, and retrieve_description option enabled, 488 * Test the download callback with valid value, and retrieve_description option enabled,
365 * but no desc or keyword defined in the page. 489 * but no desc or keyword defined in the page.
366 */ 490 */
367 public function testCurlDownloadCallbackOkWithDescNotFound() 491 public function testCurlDownloadCallbackOkWithDescNotFound(): void
368 { 492 {
493 $charset = 'utf-8';
369 $callback = get_curl_download_callback( 494 $callback = get_curl_download_callback(
370 $charset, 495 $charset,
371 $title, 496 $title,
@@ -375,24 +500,16 @@ class LinkUtilsTest extends TestCase
375 'ut_curl_getinfo_ok' 500 'ut_curl_getinfo_ok'
376 ); 501 );
377 $data = [ 502 $data = [
378 'HTTP/1.1 200 OK',
379 'Server: GitHub.com',
380 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
381 'Content-Type: text/html; charset=utf-8',
382 'Status: 200 OK',
383 'th=device-width">' 503 'th=device-width">'
384 . '<title>Refactoring · GitHub</title>' 504 . '<title>Refactoring · GitHub</title>'
385 . '<link rel="search" type="application/opensea', 505 . '<link rel="search" type="application/opensea',
386 'end' => '<title>ignored</title>', 506 'end' => '<title>ignored</title>',
387 ]; 507 ];
388 foreach ($data as $key => $line) { 508
389 $ignore = null; 509 foreach ($data as $chunk) {
390 $expected = $key !== 'end' ? strlen($line) : false; 510 static::assertSame(strlen($chunk), $callback(null, $chunk));
391 $this->assertEquals($expected, $callback($ignore, $line));
392 if ($expected === false) {
393 break;
394 }
395 } 511 }
512
396 $this->assertEquals('utf-8', $charset); 513 $this->assertEquals('utf-8', $charset);
397 $this->assertEquals('Refactoring · GitHub', $title); 514 $this->assertEquals('Refactoring · GitHub', $title);
398 $this->assertEmpty($desc); 515 $this->assertEmpty($desc);
@@ -493,6 +610,115 @@ class LinkUtilsTest extends TestCase
493 } 610 }
494 611
495 /** 612 /**
613 * Test tags_str2array with whitespace separator.
614 */
615 public function testTagsStr2ArrayWithSpaceSeparator(): void
616 {
617 $separator = ' ';
618
619 static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1 tag2 tag3', $separator));
620 static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1 tag2 tag3', $separator));
621 static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array(' tag1 tag2 tag3 ', $separator));
622 static::assertSame(['tag1@', 'tag2,', '.tag3'], tags_str2array(' tag1@ tag2, .tag3 ', $separator));
623 static::assertSame([], tags_str2array('', $separator));
624 static::assertSame([], tags_str2array(' ', $separator));
625 static::assertSame([], tags_str2array(null, $separator));
626 }
627
628 /**
629 * Test tags_str2array with @ separator.
630 */
631 public function testTagsStr2ArrayWithCharSeparator(): void
632 {
633 $separator = '@';
634
635 static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1@tag2@tag3', $separator));
636 static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('tag1@@@@tag2@@@@tag3', $separator));
637 static::assertSame(['tag1', 'tag2', 'tag3'], tags_str2array('@@@tag1@@@tag2@@@@tag3@@', $separator));
638 static::assertSame(
639 ['tag1#', 'tag2, and other', '.tag3'],
640 tags_str2array('@@@ tag1# @@@ tag2, and other @@@@.tag3@@', $separator)
641 );
642 static::assertSame([], tags_str2array('', $separator));
643 static::assertSame([], tags_str2array(' ', $separator));
644 static::assertSame([], tags_str2array(null, $separator));
645 }
646
647 /**
648 * Test tags_array2str with ' ' separator.
649 */
650 public function testTagsArray2StrWithSpaceSeparator(): void
651 {
652 $separator = ' ';
653
654 static::assertSame('tag1 tag2 tag3', tags_array2str(['tag1', 'tag2', 'tag3'], $separator));
655 static::assertSame('tag1, tag2@ tag3', tags_array2str(['tag1,', 'tag2@', 'tag3'], $separator));
656 static::assertSame('tag1 tag2 tag3', tags_array2str([' tag1 ', 'tag2', 'tag3 '], $separator));
657 static::assertSame('tag1 tag2 tag3', tags_array2str([' tag1 ', ' ', 'tag2', ' ', 'tag3 '], $separator));
658 static::assertSame('tag1', tags_array2str([' tag1 '], $separator));
659 static::assertSame('', tags_array2str([' '], $separator));
660 static::assertSame('', tags_array2str([], $separator));
661 static::assertSame('', tags_array2str(null, $separator));
662 }
663
664 /**
665 * Test tags_array2str with @ separator.
666 */
667 public function testTagsArray2StrWithCharSeparator(): void
668 {
669 $separator = '@';
670
671 static::assertSame('tag1@tag2@tag3', tags_array2str(['tag1', 'tag2', 'tag3'], $separator));
672 static::assertSame('tag1,@tag2@tag3', tags_array2str(['tag1,', 'tag2@', 'tag3'], $separator));
673 static::assertSame(
674 'tag1@tag2, and other@tag3',
675 tags_array2str(['@@@@ tag1@@@', ' @tag2, and other @', 'tag3@@@@'], $separator)
676 );
677 static::assertSame('tag1@tag2@tag3', tags_array2str(['@@@tag1@@@', '@', 'tag2', '@@@', 'tag3@@@'], $separator));
678 static::assertSame('tag1', tags_array2str(['@@@@tag1@@@@'], $separator));
679 static::assertSame('', tags_array2str(['@@@'], $separator));
680 static::assertSame('', tags_array2str([], $separator));
681 static::assertSame('', tags_array2str(null, $separator));
682 }
683
684 /**
685 * Test tags_array2str with @ separator.
686 */
687 public function testTagsFilterWithSpaceSeparator(): void
688 {
689 $separator = ' ';
690
691 static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter(['tag1', 'tag2', 'tag3'], $separator));
692 static::assertSame(['tag1,', 'tag2@', 'tag3'], tags_filter(['tag1,', 'tag2@', 'tag3'], $separator));
693 static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter([' tag1 ', 'tag2', 'tag3 '], $separator));
694 static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter([' tag1 ', ' ', 'tag2', ' ', 'tag3 '], $separator));
695 static::assertSame(['tag1'], tags_filter([' tag1 '], $separator));
696 static::assertSame([], tags_filter([' '], $separator));
697 static::assertSame([], tags_filter([], $separator));
698 static::assertSame([], tags_filter(null, $separator));
699 }
700
701 /**
702 * Test tags_array2str with @ separator.
703 */
704 public function testTagsArrayFilterWithSpaceSeparator(): void
705 {
706 $separator = '@';
707
708 static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter(['tag1', 'tag2', 'tag3'], $separator));
709 static::assertSame(['tag1,', 'tag2#', 'tag3'], tags_filter(['tag1,', 'tag2#', 'tag3'], $separator));
710 static::assertSame(
711 ['tag1', 'tag2, and other', 'tag3'],
712 tags_filter(['@@@@ tag1@@@', ' @tag2, and other @', 'tag3@@@@'], $separator)
713 );
714 static::assertSame(['tag1', 'tag2', 'tag3'], tags_filter(['@@@tag1@@@', '@', 'tag2', '@@@', 'tag3@@@'], $separator));
715 static::assertSame(['tag1'], tags_filter(['@@@@tag1@@@@'], $separator));
716 static::assertSame([], tags_filter(['@@@'], $separator));
717 static::assertSame([], tags_filter([], $separator));
718 static::assertSame([], tags_filter(null, $separator));
719 }
720
721 /**
496 * Util function to build an hashtag link. 722 * Util function to build an hashtag link.
497 * 723 *
498 * @param string $hashtag Hashtag name. 724 * @param string $hashtag Hashtag name.
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 2d675c9a..3508a7b1 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -30,3 +30,7 @@ require_once 'tests/utils/ReferenceLinkDB.php';
30require_once 'tests/utils/ReferenceSessionIdHashes.php'; 30require_once 'tests/utils/ReferenceSessionIdHashes.php';
31 31
32\ReferenceSessionIdHashes::genAllHashes(); 32\ReferenceSessionIdHashes::genAllHashes();
33
34if (!defined('SHAARLI_MUTEX_FILE')) {
35 define('SHAARLI_MUTEX_FILE', __FILE__);
36}
diff --git a/tests/container/ContainerBuilderTest.php b/tests/container/ContainerBuilderTest.php
index 5d52daef..3d43c344 100644
--- a/tests/container/ContainerBuilderTest.php
+++ b/tests/container/ContainerBuilderTest.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
4 4
5namespace Shaarli\Container; 5namespace Shaarli\Container;
6 6
7use Psr\Log\LoggerInterface;
7use Shaarli\Bookmark\BookmarkServiceInterface; 8use Shaarli\Bookmark\BookmarkServiceInterface;
8use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
9use Shaarli\Feed\FeedBuilder; 10use Shaarli\Feed\FeedBuilder;
@@ -12,6 +13,7 @@ use Shaarli\Front\Controller\Visitor\ErrorController;
12use Shaarli\Front\Controller\Visitor\ErrorNotFoundController; 13use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
13use Shaarli\History; 14use Shaarli\History;
14use Shaarli\Http\HttpAccess; 15use Shaarli\Http\HttpAccess;
16use Shaarli\Http\MetadataRetriever;
15use Shaarli\Netscape\NetscapeBookmarkUtils; 17use Shaarli\Netscape\NetscapeBookmarkUtils;
16use Shaarli\Plugin\PluginManager; 18use Shaarli\Plugin\PluginManager;
17use Shaarli\Render\PageBuilder; 19use Shaarli\Render\PageBuilder;
@@ -54,7 +56,8 @@ class ContainerBuilderTest extends TestCase
54 $this->conf, 56 $this->conf,
55 $this->sessionManager, 57 $this->sessionManager,
56 $this->cookieManager, 58 $this->cookieManager,
57 $this->loginManager 59 $this->loginManager,
60 $this->createMock(LoggerInterface::class)
58 ); 61 );
59 } 62 }
60 63
@@ -72,6 +75,8 @@ class ContainerBuilderTest extends TestCase
72 static::assertInstanceOf(History::class, $container->history); 75 static::assertInstanceOf(History::class, $container->history);
73 static::assertInstanceOf(HttpAccess::class, $container->httpAccess); 76 static::assertInstanceOf(HttpAccess::class, $container->httpAccess);
74 static::assertInstanceOf(LoginManager::class, $container->loginManager); 77 static::assertInstanceOf(LoginManager::class, $container->loginManager);
78 static::assertInstanceOf(LoggerInterface::class, $container->logger);
79 static::assertInstanceOf(MetadataRetriever::class, $container->metadataRetriever);
75 static::assertInstanceOf(NetscapeBookmarkUtils::class, $container->netscapeBookmarkUtils); 80 static::assertInstanceOf(NetscapeBookmarkUtils::class, $container->netscapeBookmarkUtils);
76 static::assertInstanceOf(PageBuilder::class, $container->pageBuilder); 81 static::assertInstanceOf(PageBuilder::class, $container->pageBuilder);
77 static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager); 82 static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager);
diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index c29e8ef3..6b9204eb 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Feed; 3namespace Shaarli\Feed;
4 4
5use DateTime; 5use DateTime;
6use malkusch\lock\mutex\NoMutex;
6use ReferenceLinkDB; 7use ReferenceLinkDB;
7use Shaarli\Bookmark\Bookmark; 8use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\BookmarkFileService; 9use Shaarli\Bookmark\BookmarkFileService;
@@ -47,6 +48,7 @@ class FeedBuilderTest extends TestCase
47 */ 48 */
48 public static function setUpBeforeClass(): void 49 public static function setUpBeforeClass(): void
49 { 50 {
51 $mutex = new NoMutex();
50 $conf = new ConfigManager('tests/utils/config/configJson'); 52 $conf = new ConfigManager('tests/utils/config/configJson');
51 $conf->set('resource.datastore', self::$testDatastore); 53 $conf->set('resource.datastore', self::$testDatastore);
52 $refLinkDB = new \ReferenceLinkDB(); 54 $refLinkDB = new \ReferenceLinkDB();
@@ -54,7 +56,7 @@ class FeedBuilderTest extends TestCase
54 $history = new History('sandbox/history.php'); 56 $history = new History('sandbox/history.php');
55 $factory = new FormatterFactory($conf, true); 57 $factory = new FormatterFactory($conf, true);
56 self::$formatter = $factory->getFormatter(); 58 self::$formatter = $factory->getFormatter();
57 self::$bookmarkService = new BookmarkFileService($conf, $history, true); 59 self::$bookmarkService = new BookmarkFileService($conf, $history, $mutex, true);
58 60
59 self::$serverInfo = array( 61 self::$serverInfo = array(
60 'HTTPS' => 'Off', 62 'HTTPS' => 'Off',
diff --git a/tests/formatter/BookmarkDefaultFormatterTest.php b/tests/formatter/BookmarkDefaultFormatterTest.php
index 9534436e..4fcc5dd1 100644
--- a/tests/formatter/BookmarkDefaultFormatterTest.php
+++ b/tests/formatter/BookmarkDefaultFormatterTest.php
@@ -174,4 +174,139 @@ class BookmarkDefaultFormatterTest extends TestCase
174 $this->assertSame($tags, $link['taglist']); 174 $this->assertSame($tags, $link['taglist']);
175 $this->assertSame(implode(' ', $tags), $link['tags']); 175 $this->assertSame(implode(' ', $tags), $link['tags']);
176 } 176 }
177
178 /**
179 * Test formatTitleHtml with search result highlight.
180 */
181 public function testFormatTitleHtmlWithSearchHighlight(): void
182 {
183 $this->formatter = new BookmarkDefaultFormatter($this->conf, false);
184
185 $bookmark = new Bookmark();
186 $bookmark->setTitle('PSR-2: Coding Style Guide');
187 $bookmark->addAdditionalContentEntry(
188 'search_highlight',
189 ['title' => [
190 ['start' => 0, 'end' => 5], // "psr-2"
191 ['start' => 7, 'end' => 13], // coding
192 ['start' => 20, 'end' => 25], // guide
193 ]]
194 );
195
196 $link = $this->formatter->format($bookmark);
197
198 $this->assertSame(
199 '<span class="search-highlight">PSR-2</span>: ' .
200 '<span class="search-highlight">Coding</span> Style ' .
201 '<span class="search-highlight">Guide</span>',
202 $link['title_html']
203 );
204 }
205
206 /**
207 * Test formatDescription with search result highlight.
208 */
209 public function testFormatDescriptionWithSearchHighlight(): void
210 {
211 $this->formatter = new BookmarkDefaultFormatter($this->conf, false);
212
213 $bookmark = new Bookmark();
214 $bookmark->setDescription('This guide extends and expands on PSR-1, the basic coding standard.');
215 $bookmark->addAdditionalContentEntry(
216 'search_highlight',
217 ['description' => [
218 ['start' => 0, 'end' => 10], // "This guide"
219 ['start' => 45, 'end' => 50], // basic
220 ['start' => 58, 'end' => 67], // standard.
221 ]]
222 );
223
224 $link = $this->formatter->format($bookmark);
225
226 $this->assertSame(
227 '<span class="search-highlight">This guide</span> extends and expands on PSR-1, the ' .
228 '<span class="search-highlight">basic</span> coding ' .
229 '<span class="search-highlight">standard.</span>',
230 $link['description']
231 );
232 }
233
234 /**
235 * Test formatUrlHtml with search result highlight.
236 */
237 public function testFormatUrlHtmlWithSearchHighlight(): void
238 {
239 $this->formatter = new BookmarkDefaultFormatter($this->conf, false);
240
241 $bookmark = new Bookmark();
242 $bookmark->setUrl('http://www.php-fig.org/psr/psr-2/');
243 $bookmark->addAdditionalContentEntry(
244 'search_highlight',
245 ['url' => [
246 ['start' => 0, 'end' => 4], // http
247 ['start' => 15, 'end' => 18], // fig
248 ['start' => 27, 'end' => 33], // "psr-2/"
249 ]]
250 );
251
252 $link = $this->formatter->format($bookmark);
253
254 $this->assertSame(
255 '<span class="search-highlight">http</span>://www.php-' .
256 '<span class="search-highlight">fig</span>.org/psr/' .
257 '<span class="search-highlight">psr-2/</span>',
258 $link['url_html']
259 );
260 }
261
262 /**
263 * Test formatTagListHtml with search result highlight.
264 */
265 public function testFormatTagListHtmlWithSearchHighlight(): void
266 {
267 $this->formatter = new BookmarkDefaultFormatter($this->conf, false);
268
269 $bookmark = new Bookmark();
270 $bookmark->setTagsString('coding-style standards quality assurance');
271 $bookmark->addAdditionalContentEntry(
272 'search_highlight',
273 ['tags' => [
274 ['start' => 0, 'end' => 12], // coding-style
275 ['start' => 23, 'end' => 30], // quality
276 ['start' => 31, 'end' => 40], // assurance
277 ],]
278 );
279
280 $link = $this->formatter->format($bookmark);
281
282 $this->assertSame(
283 [
284 '<span class="search-highlight">coding-style</span>',
285 'standards',
286 '<span class="search-highlight">quality</span>',
287 '<span class="search-highlight">assurance</span>',
288 ],
289 $link['taglist_html']
290 );
291 }
292
293 /**
294 * Test default formatting with formatter_settings.autolink set to false:
295 * URLs and hashtags should not be transformed
296 */
297 public function testFormatDescriptionWithoutLinkification(): void
298 {
299 $this->conf->set('formatter_settings.autolink', false);
300 $this->formatter = new BookmarkDefaultFormatter($this->conf, false);
301
302 $bookmark = new Bookmark();
303 $bookmark->setDescription('Hi!' . PHP_EOL . 'https://thisisaurl.tld #hashtag');
304
305 $link = $this->formatter->format($bookmark);
306
307 static::assertSame(
308 'Hi!<br />' . PHP_EOL . 'https://thisisaurl.tld &nbsp;#hashtag',
309 $link['description']
310 );
311 }
177} 312}
diff --git a/tests/formatter/BookmarkMarkdownExtraFormatterTest.php b/tests/formatter/BookmarkMarkdownExtraFormatterTest.php
new file mode 100644
index 00000000..d4941ef3
--- /dev/null
+++ b/tests/formatter/BookmarkMarkdownExtraFormatterTest.php
@@ -0,0 +1,162 @@
1<?php
2
3namespace Shaarli\Formatter;
4
5use DateTime;
6use PHPUnit\Framework\TestCase;
7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Config\ConfigManager;
9
10/**
11 * Class BookmarkMarkdownExtraFormatterTest
12 * @package Shaarli\Formatter
13 */
14class BookmarkMarkdownExtraFormatterTest extends TestCase
15{
16 /** @var string Path of test config file */
17 protected static $testConf = 'sandbox/config';
18
19 /** @var BookmarkFormatter */
20 protected $formatter;
21
22 /** @var ConfigManager instance */
23 protected $conf;
24
25 /**
26 * Initialize formatter instance.
27 */
28 public function setUp(): void
29 {
30 copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
31 $this->conf = new ConfigManager(self::$testConf);
32 $this->formatter = new BookmarkMarkdownExtraFormatter($this->conf, true);
33 }
34
35 /**
36 * Test formatting a bookmark with all its attribute filled.
37 */
38 public function testFormatExtra(): void
39 {
40 $bookmark = new Bookmark();
41 $bookmark->setId($id = 11);
42 $bookmark->setShortUrl($short = 'abcdef');
43 $bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash');
44 $bookmark->setTitle($title = 'This is a <strong>bookmark</strong>');
45 $bookmark->setDescription('<h2>Content</h2><p>`Here is some content</p>');
46 $bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '<script>alert("xss");</script>']);
47 $bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png');
48 $bookmark->setSticky(true);
49 $bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412'));
50 $bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213'));
51 $bookmark->setPrivate(true);
52
53 $link = $this->formatter->format($bookmark);
54 $this->assertEquals($id, $link['id']);
55 $this->assertEquals($short, $link['shorturl']);
56 $this->assertEquals('https://sub.domain.tld?query=here&amp;for=real#hash', $link['url']);
57 $this->assertEquals(
58 'https://sub.domain.tld?query=here&amp;for=real#hash',
59 $link['real_url']
60 );
61 $this->assertEquals('This is a &lt;strong&gt;bookmark&lt;/strong&gt;', $link['title']);
62 $this->assertEquals(
63 '<div class="markdown"><p>'.
64 '&lt;h2&gt;Content&lt;/h2&gt;&lt;p&gt;`Here is some content&lt;/p&gt;'.
65 '</p></div>',
66 $link['description']
67 );
68 $tags[3] = '&lt;script&gt;alert(&quot;xss&quot;);&lt;/script&gt;';
69 $this->assertEquals($tags, $link['taglist']);
70 $this->assertEquals(implode(' ', $tags), $link['tags']);
71 $this->assertEquals(
72 'http://domain2.tdl2/?type=img&amp;name=file.png',
73 $link['thumbnail']
74 );
75 $this->assertEquals($created, $link['created']);
76 $this->assertEquals($created->getTimestamp(), $link['timestamp']);
77 $this->assertEquals($updated, $link['updated']);
78 $this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']);
79 $this->assertTrue($link['private']);
80 $this->assertTrue($link['sticky']);
81 $this->assertEquals('private', $link['class']);
82 }
83
84 /**
85 * Test formatting a bookmark with all its attribute filled.
86 */
87 public function testFormatExtraMinimal(): void
88 {
89 $bookmark = new Bookmark();
90
91 $link = $this->formatter->format($bookmark);
92 $this->assertEmpty($link['id']);
93 $this->assertEmpty($link['shorturl']);
94 $this->assertEmpty($link['url']);
95 $this->assertEmpty($link['real_url']);
96 $this->assertEmpty($link['title']);
97 $this->assertEmpty($link['description']);
98 $this->assertEmpty($link['taglist']);
99 $this->assertEmpty($link['tags']);
100 $this->assertEmpty($link['thumbnail']);
101 $this->assertEmpty($link['created']);
102 $this->assertEmpty($link['timestamp']);
103 $this->assertEmpty($link['updated']);
104 $this->assertEmpty($link['updated_timestamp']);
105 $this->assertFalse($link['private']);
106 $this->assertFalse($link['sticky']);
107 $this->assertEmpty($link['class']);
108 }
109
110 /**
111 * Make sure that the description is properly formatted by the default formatter.
112 */
113 public function testFormatExtrraDescription(): void
114 {
115 $description = 'This a <strong>description</strong>'. PHP_EOL;
116 $description .= 'text https://sub.domain.tld?query=here&for=real#hash more text'. PHP_EOL;
117 $description .= 'Also, there is an #hashtag added'. PHP_EOL;
118 $description .= ' A N D KEEP SPACES ! '. PHP_EOL;
119 $description .= '# Header {.class}'. PHP_EOL;
120
121 $bookmark = new Bookmark();
122 $bookmark->setDescription($description);
123 $link = $this->formatter->format($bookmark);
124
125 $description = '<div class="markdown"><p>';
126 $description .= 'This a &lt;strong&gt;description&lt;/strong&gt;<br />'. PHP_EOL;
127 $url = 'https://sub.domain.tld?query=here&amp;for=real#hash';
128 $description .= 'text <a href="'. $url .'">'. $url .'</a> more text<br />'. PHP_EOL;
129 $description .= 'Also, there is an <a href="./add-tag/hashtag">#hashtag</a> added<br />'. PHP_EOL;
130 $description .= 'A N D KEEP SPACES ! </p>' . PHP_EOL;
131 $description .= '<h1 class="class">Header</h1>';
132 $description .= '</div>';
133
134 $this->assertEquals($description, $link['description']);
135 }
136
137 /**
138 * Test formatting URL with an index_url set
139 * It should prepend relative links.
140 */
141 public function testFormatExtraNoteWithIndexUrl(): void
142 {
143 $bookmark = new Bookmark();
144 $bookmark->setUrl($short = '?abcdef');
145 $description = 'Text #hashtag more text';
146 $bookmark->setDescription($description);
147
148 $this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/');
149
150 $description = '<div class="markdown"><p>';
151 $description .= 'Text <a href="'. $root .'./add-tag/hashtag">#hashtag</a> more text';
152 $description .= '</p></div>';
153
154 $link = $this->formatter->format($bookmark);
155 $this->assertEquals($root . $short, $link['url']);
156 $this->assertEquals($root . $short, $link['real_url']);
157 $this->assertEquals(
158 $description,
159 $link['description']
160 );
161 }
162}
diff --git a/tests/front/controller/admin/ConfigureControllerTest.php b/tests/front/controller/admin/ConfigureControllerTest.php
index aca6cff3..d82db0a7 100644
--- a/tests/front/controller/admin/ConfigureControllerTest.php
+++ b/tests/front/controller/admin/ConfigureControllerTest.php
@@ -51,7 +51,7 @@ class ConfigureControllerTest extends TestCase
51 static::assertSame('general.title', $assignedVariables['title']); 51 static::assertSame('general.title', $assignedVariables['title']);
52 static::assertSame('resource.theme', $assignedVariables['theme']); 52 static::assertSame('resource.theme', $assignedVariables['theme']);
53 static::assertEmpty($assignedVariables['theme_available']); 53 static::assertEmpty($assignedVariables['theme_available']);
54 static::assertSame(['default', 'markdown'], $assignedVariables['formatter_available']); 54 static::assertSame(['default', 'markdown', 'markdownExtra'], $assignedVariables['formatter_available']);
55 static::assertNotEmpty($assignedVariables['continents']); 55 static::assertNotEmpty($assignedVariables['continents']);
56 static::assertNotEmpty($assignedVariables['cities']); 56 static::assertNotEmpty($assignedVariables['cities']);
57 static::assertSame('general.retrieve_description', $assignedVariables['retrieve_description']); 57 static::assertSame('general.retrieve_description', $assignedVariables['retrieve_description']);
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php b/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
deleted file mode 100644
index 0f27ec2f..00000000
--- a/tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
+++ /dev/null
@@ -1,47 +0,0 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
6
7use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
8use Shaarli\Front\Controller\Admin\ManageShaareController;
9use Shaarli\Http\HttpAccess;
10use Shaarli\TestCase;
11use Slim\Http\Request;
12use Slim\Http\Response;
13
14class AddShaareTest extends TestCase
15{
16 use FrontAdminControllerMockHelper;
17
18 /** @var ManageShaareController */
19 protected $controller;
20
21 public function setUp(): void
22 {
23 $this->createContainer();
24
25 $this->container->httpAccess = $this->createMock(HttpAccess::class);
26 $this->controller = new ManageShaareController($this->container);
27 }
28
29 /**
30 * Test displaying add link page
31 */
32 public function testAddShaare(): void
33 {
34 $assignedVariables = [];
35 $this->assignTemplateVars($assignedVariables);
36
37 $request = $this->createMock(Request::class);
38 $response = new Response();
39
40 $result = $this->controller->addShaare($request, $response);
41
42 static::assertSame(200, $result->getStatusCode());
43 static::assertSame('addlink', (string) $result->getBody());
44
45 static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']);
46 }
47}
diff --git a/tests/front/controller/admin/ManageTagControllerTest.php b/tests/front/controller/admin/ManageTagControllerTest.php
index 8a0ff7a9..af6f273f 100644
--- a/tests/front/controller/admin/ManageTagControllerTest.php
+++ b/tests/front/controller/admin/ManageTagControllerTest.php
@@ -6,6 +6,7 @@ namespace Shaarli\Front\Controller\Admin;
6 6
7use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\BookmarkFilter; 8use Shaarli\Bookmark\BookmarkFilter;
9use Shaarli\Config\ConfigManager;
9use Shaarli\Front\Exception\WrongTokenException; 10use Shaarli\Front\Exception\WrongTokenException;
10use Shaarli\Security\SessionManager; 11use Shaarli\Security\SessionManager;
11use Shaarli\TestCase; 12use Shaarli\TestCase;
@@ -44,10 +45,33 @@ class ManageTagControllerTest extends TestCase
44 static::assertSame('changetag', (string) $result->getBody()); 45 static::assertSame('changetag', (string) $result->getBody());
45 46
46 static::assertSame('fromtag', $assignedVariables['fromtag']); 47 static::assertSame('fromtag', $assignedVariables['fromtag']);
48 static::assertSame('@', $assignedVariables['tags_separator']);
47 static::assertSame('Manage tags - Shaarli', $assignedVariables['pagetitle']); 49 static::assertSame('Manage tags - Shaarli', $assignedVariables['pagetitle']);
48 } 50 }
49 51
50 /** 52 /**
53 * Test displaying manage tag page
54 */
55 public function testIndexWhitespaceSeparator(): void
56 {
57 $assignedVariables = [];
58 $this->assignTemplateVars($assignedVariables);
59
60 $this->container->conf = $this->createMock(ConfigManager::class);
61 $this->container->conf->method('get')->willReturnCallback(function (string $key) {
62 return $key === 'general.tags_separator' ? ' ' : $key;
63 });
64
65 $request = $this->createMock(Request::class);
66 $response = new Response();
67
68 $this->controller->index($request, $response);
69
70 static::assertSame('&nbsp;', $assignedVariables['tags_separator']);
71 static::assertSame('whitespace', $assignedVariables['tags_separator_desc']);
72 }
73
74 /**
51 * Test posting a tag update - rename tag - valid info provided. 75 * Test posting a tag update - rename tag - valid info provided.
52 */ 76 */
53 public function testSaveRenameTagValid(): void 77 public function testSaveRenameTagValid(): void
@@ -269,4 +293,116 @@ class ManageTagControllerTest extends TestCase
269 static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session); 293 static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
270 static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]); 294 static::assertSame(['Invalid tags provided.'], $session[SessionManager::KEY_WARNING_MESSAGES]);
271 } 295 }
296
297 /**
298 * Test changeSeparator to '#': redirection + success message.
299 */
300 public function testChangeSeparatorValid(): void
301 {
302 $toSeparator = '#';
303
304 $session = [];
305 $this->assignSessionVars($session);
306
307 $request = $this->createMock(Request::class);
308 $request
309 ->expects(static::atLeastOnce())
310 ->method('getParam')
311 ->willReturnCallback(function (string $key) use ($toSeparator): ?string {
312 return $key === 'separator' ? $toSeparator : $key;
313 })
314 ;
315 $response = new Response();
316
317 $this->container->conf
318 ->expects(static::once())
319 ->method('set')
320 ->with('general.tags_separator', $toSeparator, true, true)
321 ;
322
323 $result = $this->controller->changeSeparator($request, $response);
324
325 static::assertSame(302, $result->getStatusCode());
326 static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
327
328 static::assertArrayNotHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
329 static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
330 static::assertArrayHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
331 static::assertSame(
332 ['Your tags separator setting has been updated!'],
333 $session[SessionManager::KEY_SUCCESS_MESSAGES]
334 );
335 }
336
337 /**
338 * Test changeSeparator to '#@' (too long): redirection + error message.
339 */
340 public function testChangeSeparatorInvalidTooLong(): void
341 {
342 $toSeparator = '#@';
343
344 $session = [];
345 $this->assignSessionVars($session);
346
347 $request = $this->createMock(Request::class);
348 $request
349 ->expects(static::atLeastOnce())
350 ->method('getParam')
351 ->willReturnCallback(function (string $key) use ($toSeparator): ?string {
352 return $key === 'separator' ? $toSeparator : $key;
353 })
354 ;
355 $response = new Response();
356
357 $this->container->conf->expects(static::never())->method('set');
358
359 $result = $this->controller->changeSeparator($request, $response);
360
361 static::assertSame(302, $result->getStatusCode());
362 static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
363
364 static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
365 static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
366 static::assertArrayHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
367 static::assertSame(
368 ['Tags separator must be a single character.'],
369 $session[SessionManager::KEY_ERROR_MESSAGES]
370 );
371 }
372
373 /**
374 * Test changeSeparator to '#@' (too long): redirection + error message.
375 */
376 public function testChangeSeparatorInvalidReservedCharacter(): void
377 {
378 $toSeparator = '*';
379
380 $session = [];
381 $this->assignSessionVars($session);
382
383 $request = $this->createMock(Request::class);
384 $request
385 ->expects(static::atLeastOnce())
386 ->method('getParam')
387 ->willReturnCallback(function (string $key) use ($toSeparator): ?string {
388 return $key === 'separator' ? $toSeparator : $key;
389 })
390 ;
391 $response = new Response();
392
393 $this->container->conf->expects(static::never())->method('set');
394
395 $result = $this->controller->changeSeparator($request, $response);
396
397 static::assertSame(302, $result->getStatusCode());
398 static::assertSame(['/subfolder/admin/tags'], $result->getHeader('location'));
399
400 static::assertArrayNotHasKey(SessionManager::KEY_SUCCESS_MESSAGES, $session);
401 static::assertArrayNotHasKey(SessionManager::KEY_WARNING_MESSAGES, $session);
402 static::assertArrayHasKey(SessionManager::KEY_ERROR_MESSAGES, $session);
403 static::assertStringStartsWith(
404 'These characters are reserved and can\'t be used as tags separator',
405 $session[SessionManager::KEY_ERROR_MESSAGES][0]
406 );
407 }
272} 408}
diff --git a/tests/front/controller/admin/ServerControllerTest.php b/tests/front/controller/admin/ServerControllerTest.php
new file mode 100644
index 00000000..355cce7d
--- /dev/null
+++ b/tests/front/controller/admin/ServerControllerTest.php
@@ -0,0 +1,184 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin;
6
7use Shaarli\Config\ConfigManager;
8use Shaarli\Security\SessionManager;
9use Shaarli\TestCase;
10use Slim\Http\Request;
11use Slim\Http\Response;
12
13/**
14 * Test Server administration controller.
15 */
16class ServerControllerTest extends TestCase
17{
18 use FrontAdminControllerMockHelper;
19
20 /** @var ServerController */
21 protected $controller;
22
23 public function setUp(): void
24 {
25 $this->createContainer();
26
27 $this->controller = new ServerController($this->container);
28
29 // initialize dummy cache
30 @mkdir('sandbox/');
31 foreach (['pagecache', 'tmp', 'cache'] as $folder) {
32 @mkdir('sandbox/' . $folder);
33 @touch('sandbox/' . $folder . '/.htaccess');
34 @touch('sandbox/' . $folder . '/1');
35 @touch('sandbox/' . $folder . '/2');
36 }
37 }
38
39 public function tearDown(): void
40 {
41 foreach (['pagecache', 'tmp', 'cache'] as $folder) {
42 @unlink('sandbox/' . $folder . '/.htaccess');
43 @unlink('sandbox/' . $folder . '/1');
44 @unlink('sandbox/' . $folder . '/2');
45 @rmdir('sandbox/' . $folder);
46 }
47 }
48
49 /**
50 * Test default display of server administration page.
51 */
52 public function testIndex(): void
53 {
54 $request = $this->createMock(Request::class);
55 $response = new Response();
56
57 // Save RainTPL assigned variables
58 $assignedVariables = [];
59 $this->assignTemplateVars($assignedVariables);
60
61 $result = $this->controller->index($request, $response);
62
63 static::assertSame(200, $result->getStatusCode());
64 static::assertSame('server', (string) $result->getBody());
65
66 static::assertSame(PHP_VERSION, $assignedVariables['php_version']);
67 static::assertArrayHasKey('php_has_reached_eol', $assignedVariables);
68 static::assertArrayHasKey('php_eol', $assignedVariables);
69 static::assertArrayHasKey('php_extensions', $assignedVariables);
70 static::assertArrayHasKey('permissions', $assignedVariables);
71 static::assertEmpty($assignedVariables['permissions']);
72
73 static::assertRegExp(
74 '#https://github\.com/shaarli/Shaarli/releases/tag/v\d+\.\d+\.\d+#',
75 $assignedVariables['release_url']
76 );
77 static::assertRegExp('#v\d+\.\d+\.\d+#', $assignedVariables['latest_version']);
78 static::assertRegExp('#(v\d+\.\d+\.\d+|dev)#', $assignedVariables['current_version']);
79 static::assertArrayHasKey('index_url', $assignedVariables);
80 static::assertArrayHasKey('client_ip', $assignedVariables);
81 static::assertArrayHasKey('trusted_proxies', $assignedVariables);
82
83 static::assertSame('Server administration - Shaarli', $assignedVariables['pagetitle']);
84 }
85
86 /**
87 * Test clearing the main cache
88 */
89 public function testClearMainCache(): void
90 {
91 $this->container->conf = $this->createMock(ConfigManager::class);
92 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
93 if ($key === 'resource.page_cache') {
94 return 'sandbox/pagecache';
95 } elseif ($key === 'resource.raintpl_tmp') {
96 return 'sandbox/tmp';
97 } elseif ($key === 'resource.thumbnails_cache') {
98 return 'sandbox/cache';
99 } else {
100 return $default;
101 }
102 });
103
104 $this->container->sessionManager
105 ->expects(static::once())
106 ->method('setSessionParameter')
107 ->with(SessionManager::KEY_SUCCESS_MESSAGES, ['Shaarli\'s cache folder has been cleared!'])
108 ;
109
110 $request = $this->createMock(Request::class);
111 $request->method('getQueryParam')->with('type')->willReturn('main');
112 $response = new Response();
113
114 $result = $this->controller->clearCache($request, $response);
115
116 static::assertSame(302, $result->getStatusCode());
117 static::assertSame('/subfolder/admin/server', (string) $result->getHeaderLine('Location'));
118
119 static::assertFileNotExists('sandbox/pagecache/1');
120 static::assertFileNotExists('sandbox/pagecache/2');
121 static::assertFileNotExists('sandbox/tmp/1');
122 static::assertFileNotExists('sandbox/tmp/2');
123
124 static::assertFileExists('sandbox/pagecache/.htaccess');
125 static::assertFileExists('sandbox/tmp/.htaccess');
126 static::assertFileExists('sandbox/cache');
127 static::assertFileExists('sandbox/cache/.htaccess');
128 static::assertFileExists('sandbox/cache/1');
129 static::assertFileExists('sandbox/cache/2');
130 }
131
132 /**
133 * Test clearing thumbnails cache
134 */
135 public function testClearThumbnailsCache(): void
136 {
137 $this->container->conf = $this->createMock(ConfigManager::class);
138 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
139 if ($key === 'resource.page_cache') {
140 return 'sandbox/pagecache';
141 } elseif ($key === 'resource.raintpl_tmp') {
142 return 'sandbox/tmp';
143 } elseif ($key === 'resource.thumbnails_cache') {
144 return 'sandbox/cache';
145 } else {
146 return $default;
147 }
148 });
149
150 $this->container->sessionManager
151 ->expects(static::once())
152 ->method('setSessionParameter')
153 ->willReturnCallback(function (string $key, array $value): SessionManager {
154 static::assertSame(SessionManager::KEY_WARNING_MESSAGES, $key);
155 static::assertCount(1, $value);
156 static::assertStringStartsWith('Thumbnails cache has been cleared.', $value[0]);
157
158 return $this->container->sessionManager;
159 });
160 ;
161
162 $request = $this->createMock(Request::class);
163 $request->method('getQueryParam')->with('type')->willReturn('thumbnails');
164 $response = new Response();
165
166 $result = $this->controller->clearCache($request, $response);
167
168 static::assertSame(302, $result->getStatusCode());
169 static::assertSame('/subfolder/admin/server', (string) $result->getHeaderLine('Location'));
170
171 static::assertFileNotExists('sandbox/cache/1');
172 static::assertFileNotExists('sandbox/cache/2');
173
174 static::assertFileExists('sandbox/cache/.htaccess');
175 static::assertFileExists('sandbox/pagecache');
176 static::assertFileExists('sandbox/pagecache/.htaccess');
177 static::assertFileExists('sandbox/pagecache/1');
178 static::assertFileExists('sandbox/pagecache/2');
179 static::assertFileExists('sandbox/tmp');
180 static::assertFileExists('sandbox/tmp/.htaccess');
181 static::assertFileExists('sandbox/tmp/1');
182 static::assertFileExists('sandbox/tmp/2');
183 }
184}
diff --git a/tests/front/controller/admin/ShaareAddControllerTest.php b/tests/front/controller/admin/ShaareAddControllerTest.php
new file mode 100644
index 00000000..a27ebe64
--- /dev/null
+++ b/tests/front/controller/admin/ShaareAddControllerTest.php
@@ -0,0 +1,97 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin;
6
7use Shaarli\Config\ConfigManager;
8use Shaarli\Formatter\BookmarkMarkdownFormatter;
9use Shaarli\Http\HttpAccess;
10use Shaarli\TestCase;
11use Slim\Http\Request;
12use Slim\Http\Response;
13
14class ShaareAddControllerTest extends TestCase
15{
16 use FrontAdminControllerMockHelper;
17
18 /** @var ShaareAddController */
19 protected $controller;
20
21 public function setUp(): void
22 {
23 $this->createContainer();
24
25 $this->container->httpAccess = $this->createMock(HttpAccess::class);
26 $this->controller = new ShaareAddController($this->container);
27 }
28
29 /**
30 * Test displaying add link page
31 */
32 public function testAddShaare(): void
33 {
34 $assignedVariables = [];
35 $this->assignTemplateVars($assignedVariables);
36
37 $request = $this->createMock(Request::class);
38 $response = new Response();
39
40 $expectedTags = [
41 'tag1' => 32,
42 'tag2' => 24,
43 'tag3' => 1,
44 ];
45 $this->container->bookmarkService
46 ->expects(static::once())
47 ->method('bookmarksCountPerTag')
48 ->willReturn($expectedTags)
49 ;
50 $expectedTags = array_merge($expectedTags, [BookmarkMarkdownFormatter::NO_MD_TAG => 1]);
51
52 $this->container->conf = $this->createMock(ConfigManager::class);
53 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
54 return $key === 'formatter' ? 'markdown' : $default;
55 });
56
57 $result = $this->controller->addShaare($request, $response);
58
59 static::assertSame(200, $result->getStatusCode());
60 static::assertSame('addlink', (string) $result->getBody());
61
62 static::assertSame('Shaare a new link - Shaarli', $assignedVariables['pagetitle']);
63 static::assertFalse($assignedVariables['default_private_links']);
64 static::assertTrue($assignedVariables['async_metadata']);
65 static::assertSame($expectedTags, $assignedVariables['tags']);
66 }
67
68 /**
69 * Test displaying add link page
70 */
71 public function testAddShaareWithoutMd(): void
72 {
73 $assignedVariables = [];
74 $this->assignTemplateVars($assignedVariables);
75
76 $request = $this->createMock(Request::class);
77 $response = new Response();
78
79 $expectedTags = [
80 'tag1' => 32,
81 'tag2' => 24,
82 'tag3' => 1,
83 ];
84 $this->container->bookmarkService
85 ->expects(static::once())
86 ->method('bookmarksCountPerTag')
87 ->willReturn($expectedTags)
88 ;
89
90 $result = $this->controller->addShaare($request, $response);
91
92 static::assertSame(200, $result->getStatusCode());
93 static::assertSame('addlink', (string) $result->getBody());
94
95 static::assertSame($expectedTags, $assignedVariables['tags']);
96 }
97}
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php b/tests/front/controller/admin/ShaareManageControllerTest/ChangeVisibilityBookmarkTest.php
index 096d0774..28b1c023 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php
+++ b/tests/front/controller/admin/ShaareManageControllerTest/ChangeVisibilityBookmarkTest.php
@@ -2,7 +2,7 @@
2 2
3declare(strict_types=1); 3declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest; 5namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
6 6
7use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 8use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
@@ -10,7 +10,7 @@ use Shaarli\Formatter\BookmarkFormatter;
10use Shaarli\Formatter\BookmarkRawFormatter; 10use Shaarli\Formatter\BookmarkRawFormatter;
11use Shaarli\Formatter\FormatterFactory; 11use Shaarli\Formatter\FormatterFactory;
12use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper; 12use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
13use Shaarli\Front\Controller\Admin\ManageShaareController; 13use Shaarli\Front\Controller\Admin\ShaareManageController;
14use Shaarli\Http\HttpAccess; 14use Shaarli\Http\HttpAccess;
15use Shaarli\Security\SessionManager; 15use Shaarli\Security\SessionManager;
16use Shaarli\TestCase; 16use Shaarli\TestCase;
@@ -21,7 +21,7 @@ class ChangeVisibilityBookmarkTest extends TestCase
21{ 21{
22 use FrontAdminControllerMockHelper; 22 use FrontAdminControllerMockHelper;
23 23
24 /** @var ManageShaareController */ 24 /** @var ShaareManageController */
25 protected $controller; 25 protected $controller;
26 26
27 public function setUp(): void 27 public function setUp(): void
@@ -29,7 +29,7 @@ class ChangeVisibilityBookmarkTest extends TestCase
29 $this->createContainer(); 29 $this->createContainer();
30 30
31 $this->container->httpAccess = $this->createMock(HttpAccess::class); 31 $this->container->httpAccess = $this->createMock(HttpAccess::class);
32 $this->controller = new ManageShaareController($this->container); 32 $this->controller = new ShaareManageController($this->container);
33 } 33 }
34 34
35 /** 35 /**
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php b/tests/front/controller/admin/ShaareManageControllerTest/DeleteBookmarkTest.php
index ba774e21..a276d988 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
+++ b/tests/front/controller/admin/ShaareManageControllerTest/DeleteBookmarkTest.php
@@ -2,14 +2,14 @@
2 2
3declare(strict_types=1); 3declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest; 5namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
6 6
7use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 8use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9use Shaarli\Formatter\BookmarkFormatter; 9use Shaarli\Formatter\BookmarkFormatter;
10use Shaarli\Formatter\FormatterFactory; 10use Shaarli\Formatter\FormatterFactory;
11use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper; 11use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
12use Shaarli\Front\Controller\Admin\ManageShaareController; 12use Shaarli\Front\Controller\Admin\ShaareManageController;
13use Shaarli\Http\HttpAccess; 13use Shaarli\Http\HttpAccess;
14use Shaarli\Security\SessionManager; 14use Shaarli\Security\SessionManager;
15use Shaarli\TestCase; 15use Shaarli\TestCase;
@@ -20,7 +20,7 @@ class DeleteBookmarkTest extends TestCase
20{ 20{
21 use FrontAdminControllerMockHelper; 21 use FrontAdminControllerMockHelper;
22 22
23 /** @var ManageShaareController */ 23 /** @var ShaareManageController */
24 protected $controller; 24 protected $controller;
25 25
26 public function setUp(): void 26 public function setUp(): void
@@ -28,7 +28,7 @@ class DeleteBookmarkTest extends TestCase
28 $this->createContainer(); 28 $this->createContainer();
29 29
30 $this->container->httpAccess = $this->createMock(HttpAccess::class); 30 $this->container->httpAccess = $this->createMock(HttpAccess::class);
31 $this->controller = new ManageShaareController($this->container); 31 $this->controller = new ShaareManageController($this->container);
32 } 32 }
33 33
34 /** 34 /**
@@ -38,6 +38,8 @@ class DeleteBookmarkTest extends TestCase
38 { 38 {
39 $parameters = ['id' => '123']; 39 $parameters = ['id' => '123'];
40 40
41 $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/shaare/abcdef';
42
41 $request = $this->createMock(Request::class); 43 $request = $this->createMock(Request::class);
42 $request 44 $request
43 ->method('getParam') 45 ->method('getParam')
@@ -90,6 +92,8 @@ class DeleteBookmarkTest extends TestCase
90 { 92 {
91 $parameters = ['id' => '123 456 789']; 93 $parameters = ['id' => '123 456 789'];
92 94
95 $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/?searchtags=abcdef';
96
93 $request = $this->createMock(Request::class); 97 $request = $this->createMock(Request::class);
94 $request 98 $request
95 ->method('getParam') 99 ->method('getParam')
@@ -152,7 +156,7 @@ class DeleteBookmarkTest extends TestCase
152 $result = $this->controller->deleteBookmark($request, $response); 156 $result = $this->controller->deleteBookmark($request, $response);
153 157
154 static::assertSame(302, $result->getStatusCode()); 158 static::assertSame(302, $result->getStatusCode());
155 static::assertSame(['/subfolder/'], $result->getHeader('location')); 159 static::assertSame(['/subfolder/?searchtags=abcdef'], $result->getHeader('location'));
156 } 160 }
157 161
158 /** 162 /**
@@ -356,6 +360,10 @@ class DeleteBookmarkTest extends TestCase
356 ; 360 ;
357 $response = new Response(); 361 $response = new Response();
358 362
363 $this->container->bookmarkService->method('get')->with('123')->willReturn(
364 (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123')
365 );
366
359 $this->container->formatterFactory = $this->createMock(FormatterFactory::class); 367 $this->container->formatterFactory = $this->createMock(FormatterFactory::class);
360 $this->container->formatterFactory 368 $this->container->formatterFactory
361 ->expects(static::once()) 369 ->expects(static::once())
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php b/tests/front/controller/admin/ShaareManageControllerTest/PinBookmarkTest.php
index 50ce7df1..b89206ce 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php
+++ b/tests/front/controller/admin/ShaareManageControllerTest/PinBookmarkTest.php
@@ -2,12 +2,12 @@
2 2
3declare(strict_types=1); 3declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest; 5namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
6 6
7use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 8use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper; 9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
10use Shaarli\Front\Controller\Admin\ManageShaareController; 10use Shaarli\Front\Controller\Admin\ShaareManageController;
11use Shaarli\Http\HttpAccess; 11use Shaarli\Http\HttpAccess;
12use Shaarli\Security\SessionManager; 12use Shaarli\Security\SessionManager;
13use Shaarli\TestCase; 13use Shaarli\TestCase;
@@ -18,7 +18,7 @@ class PinBookmarkTest extends TestCase
18{ 18{
19 use FrontAdminControllerMockHelper; 19 use FrontAdminControllerMockHelper;
20 20
21 /** @var ManageShaareController */ 21 /** @var ShaareManageController */
22 protected $controller; 22 protected $controller;
23 23
24 public function setUp(): void 24 public function setUp(): void
@@ -26,7 +26,7 @@ class PinBookmarkTest extends TestCase
26 $this->createContainer(); 26 $this->createContainer();
27 27
28 $this->container->httpAccess = $this->createMock(HttpAccess::class); 28 $this->container->httpAccess = $this->createMock(HttpAccess::class);
29 $this->controller = new ManageShaareController($this->container); 29 $this->controller = new ShaareManageController($this->container);
30 } 30 }
31 31
32 /** 32 /**
diff --git a/tests/front/controller/admin/ShaareManageControllerTest/SharePrivateTest.php b/tests/front/controller/admin/ShaareManageControllerTest/SharePrivateTest.php
new file mode 100644
index 00000000..ae61dfb7
--- /dev/null
+++ b/tests/front/controller/admin/ShaareManageControllerTest/SharePrivateTest.php
@@ -0,0 +1,139 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ShaareManageControllerTest;
6
7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
9use Shaarli\Front\Controller\Admin\ShaareManageController;
10use Shaarli\Http\HttpAccess;
11use Shaarli\TestCase;
12use Slim\Http\Request;
13use Slim\Http\Response;
14
15/**
16 * Test GET /admin/shaare/private/{hash}
17 */
18class SharePrivateTest extends TestCase
19{
20 use FrontAdminControllerMockHelper;
21
22 /** @var ShaareManageController */
23 protected $controller;
24
25 public function setUp(): void
26 {
27 $this->createContainer();
28
29 $this->container->httpAccess = $this->createMock(HttpAccess::class);
30 $this->controller = new ShaareManageController($this->container);
31 }
32
33 /**
34 * Test shaare private with a private bookmark which does not have a key yet.
35 */
36 public function testSharePrivateWithNewPrivateBookmark(): void
37 {
38 $hash = 'abcdcef';
39 $request = $this->createMock(Request::class);
40 $response = new Response();
41
42 $bookmark = (new Bookmark())
43 ->setId(123)
44 ->setUrl('http://domain.tld')
45 ->setTitle('Title 123')
46 ->setPrivate(true)
47 ;
48
49 $this->container->bookmarkService
50 ->expects(static::once())
51 ->method('findByHash')
52 ->with($hash)
53 ->willReturn($bookmark)
54 ;
55 $this->container->bookmarkService
56 ->expects(static::once())
57 ->method('set')
58 ->with($bookmark, true)
59 ->willReturnCallback(function (Bookmark $bookmark): Bookmark {
60 static::assertSame(32, strlen($bookmark->getAdditionalContentEntry('private_key')));
61
62 return $bookmark;
63 })
64 ;
65
66 $result = $this->controller->sharePrivate($request, $response, ['hash' => $hash]);
67
68 static::assertSame(302, $result->getStatusCode());
69 static::assertRegExp('#/subfolder/shaare/' . $hash . '\?key=\w{32}#', $result->getHeaderLine('Location'));
70 }
71
72 /**
73 * Test shaare private with a private bookmark which does already have a key.
74 */
75 public function testSharePrivateWithExistingPrivateBookmark(): void
76 {
77 $hash = 'abcdcef';
78 $existingKey = 'this is a private key';
79 $request = $this->createMock(Request::class);
80 $response = new Response();
81
82 $bookmark = (new Bookmark())
83 ->setId(123)
84 ->setUrl('http://domain.tld')
85 ->setTitle('Title 123')
86 ->setPrivate(true)
87 ->addAdditionalContentEntry('private_key', $existingKey)
88 ;
89
90 $this->container->bookmarkService
91 ->expects(static::once())
92 ->method('findByHash')
93 ->with($hash)
94 ->willReturn($bookmark)
95 ;
96 $this->container->bookmarkService
97 ->expects(static::never())
98 ->method('set')
99 ;
100
101 $result = $this->controller->sharePrivate($request, $response, ['hash' => $hash]);
102
103 static::assertSame(302, $result->getStatusCode());
104 static::assertSame('/subfolder/shaare/' . $hash . '?key=' . $existingKey, $result->getHeaderLine('Location'));
105 }
106
107 /**
108 * Test shaare private with a public bookmark.
109 */
110 public function testSharePrivateWithPublicBookmark(): void
111 {
112 $hash = 'abcdcef';
113 $request = $this->createMock(Request::class);
114 $response = new Response();
115
116 $bookmark = (new Bookmark())
117 ->setId(123)
118 ->setUrl('http://domain.tld')
119 ->setTitle('Title 123')
120 ->setPrivate(false)
121 ;
122
123 $this->container->bookmarkService
124 ->expects(static::once())
125 ->method('findByHash')
126 ->with($hash)
127 ->willReturn($bookmark)
128 ;
129 $this->container->bookmarkService
130 ->expects(static::never())
131 ->method('set')
132 ;
133
134 $result = $this->controller->sharePrivate($request, $response, ['hash' => $hash]);
135
136 static::assertSame(302, $result->getStatusCode());
137 static::assertSame('/subfolder/shaare/' . $hash, $result->getHeaderLine('Location'));
138 }
139}
diff --git a/tests/front/controller/admin/ShaarePublishControllerTest/DisplayCreateBatchFormTest.php b/tests/front/controller/admin/ShaarePublishControllerTest/DisplayCreateBatchFormTest.php
new file mode 100644
index 00000000..ce8e112b
--- /dev/null
+++ b/tests/front/controller/admin/ShaarePublishControllerTest/DisplayCreateBatchFormTest.php
@@ -0,0 +1,63 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
6
7use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
8use Shaarli\Front\Controller\Admin\ShaarePublishController;
9use Shaarli\Http\HttpAccess;
10use Shaarli\Http\MetadataRetriever;
11use Shaarli\TestCase;
12use Slim\Http\Request;
13use Slim\Http\Response;
14
15class DisplayCreateBatchFormTest extends TestCase
16{
17 use FrontAdminControllerMockHelper;
18
19 /** @var ShaarePublishController */
20 protected $controller;
21
22 public function setUp(): void
23 {
24 $this->createContainer();
25
26 $this->container->httpAccess = $this->createMock(HttpAccess::class);
27 $this->container->metadataRetriever = $this->createMock(MetadataRetriever::class);
28 $this->controller = new ShaarePublishController($this->container);
29 }
30
31 /**
32 * TODO
33 */
34 public function testDisplayCreateFormBatch(): void
35 {
36 $urls = [
37 'https://domain1.tld/url1',
38 'https://domain2.tld/url2',
39 ' ',
40 'https://domain3.tld/url3',
41 ];
42
43 $request = $this->createMock(Request::class);
44 $request->method('getParam')->willReturnCallback(function (string $key) use ($urls): ?string {
45 return $key === 'urls' ? implode(PHP_EOL, $urls) : null;
46 });
47 $response = new Response();
48
49 $assignedVariables = [];
50 $this->assignTemplateVars($assignedVariables);
51
52 $result = $this->controller->displayCreateBatchForms($request, $response);
53
54 static::assertSame(200, $result->getStatusCode());
55 static::assertSame('editlink.batch', (string) $result->getBody());
56
57 static::assertTrue($assignedVariables['batch_mode']);
58 static::assertCount(3, $assignedVariables['links']);
59 static::assertSame($urls[0], $assignedVariables['links'][0]['link']['url']);
60 static::assertSame($urls[1], $assignedVariables['links'][1]['link']['url']);
61 static::assertSame($urls[3], $assignedVariables['links'][2]['link']['url']);
62 }
63}
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php b/tests/front/controller/admin/ShaarePublishControllerTest/DisplayCreateFormTest.php
index 2eb95251..964773da 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php
+++ b/tests/front/controller/admin/ShaarePublishControllerTest/DisplayCreateFormTest.php
@@ -2,13 +2,14 @@
2 2
3declare(strict_types=1); 3declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest; 5namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
6 6
7use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper; 9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
10use Shaarli\Front\Controller\Admin\ManageShaareController; 10use Shaarli\Front\Controller\Admin\ShaarePublishController;
11use Shaarli\Http\HttpAccess; 11use Shaarli\Http\HttpAccess;
12use Shaarli\Http\MetadataRetriever;
12use Shaarli\TestCase; 13use Shaarli\TestCase;
13use Slim\Http\Request; 14use Slim\Http\Request;
14use Slim\Http\Response; 15use Slim\Http\Response;
@@ -17,7 +18,7 @@ class DisplayCreateFormTest extends TestCase
17{ 18{
18 use FrontAdminControllerMockHelper; 19 use FrontAdminControllerMockHelper;
19 20
20 /** @var ManageShaareController */ 21 /** @var ShaarePublishController */
21 protected $controller; 22 protected $controller;
22 23
23 public function setUp(): void 24 public function setUp(): void
@@ -25,14 +26,15 @@ class DisplayCreateFormTest extends TestCase
25 $this->createContainer(); 26 $this->createContainer();
26 27
27 $this->container->httpAccess = $this->createMock(HttpAccess::class); 28 $this->container->httpAccess = $this->createMock(HttpAccess::class);
28 $this->controller = new ManageShaareController($this->container); 29 $this->container->metadataRetriever = $this->createMock(MetadataRetriever::class);
30 $this->controller = new ShaarePublishController($this->container);
29 } 31 }
30 32
31 /** 33 /**
32 * Test displaying bookmark create form 34 * Test displaying bookmark create form
33 * Ensure that every step of the standard workflow works properly. 35 * Ensure that every step of the standard workflow works properly.
34 */ 36 */
35 public function testDisplayCreateFormWithUrl(): void 37 public function testDisplayCreateFormWithUrlAndWithMetadataRetrieval(): void
36 { 38 {
37 $this->container->environment = [ 39 $this->container->environment = [
38 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc' 40 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc'
@@ -53,40 +55,20 @@ class DisplayCreateFormTest extends TestCase
53 }); 55 });
54 $response = new Response(); 56 $response = new Response();
55 57
56 $this->container->httpAccess 58 $this->container->conf = $this->createMock(ConfigManager::class);
57 ->expects(static::once()) 59 $this->container->conf->method('get')->willReturnCallback(function (string $param, $default) {
58 ->method('getCurlDownloadCallback') 60 if ($param === 'general.enable_async_metadata') {
59 ->willReturnCallback( 61 return false;
60 function (&$charset, &$title, &$description, &$tags) use ( 62 }
61 $remoteTitle, 63
62 $remoteDesc, 64 return $default;
63 $remoteTags 65 });
64 ): callable { 66
65 return function () use ( 67 $this->container->metadataRetriever->expects(static::once())->method('retrieve')->willReturn([
66 &$charset, 68 'title' => $remoteTitle,
67 &$title, 69 'description' => $remoteDesc,
68 &$description, 70 'tags' => $remoteTags,
69 &$tags, 71 ]);
70 $remoteTitle,
71 $remoteDesc,
72 $remoteTags
73 ): void {
74 $charset = 'ISO-8859-1';
75 $title = $remoteTitle;
76 $description = $remoteDesc;
77 $tags = $remoteTags;
78 };
79 }
80 )
81 ;
82 $this->container->httpAccess
83 ->expects(static::once())
84 ->method('getHttpResponse')
85 ->with($expectedUrl, 30, 4194304)
86 ->willReturnCallback(function($url, $timeout, $maxBytes, $callback): void {
87 $callback();
88 })
89 ;
90 72
91 $this->container->bookmarkService 73 $this->container->bookmarkService
92 ->expects(static::once()) 74 ->expects(static::once())
@@ -119,7 +101,73 @@ class DisplayCreateFormTest extends TestCase
119 static::assertSame($expectedUrl, $assignedVariables['link']['url']); 101 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
120 static::assertSame($remoteTitle, $assignedVariables['link']['title']); 102 static::assertSame($remoteTitle, $assignedVariables['link']['title']);
121 static::assertSame($remoteDesc, $assignedVariables['link']['description']); 103 static::assertSame($remoteDesc, $assignedVariables['link']['description']);
122 static::assertSame($remoteTags, $assignedVariables['link']['tags']); 104 static::assertSame($remoteTags . ' ', $assignedVariables['link']['tags']);
105 static::assertFalse($assignedVariables['link']['private']);
106
107 static::assertTrue($assignedVariables['link_is_new']);
108 static::assertSame($referer, $assignedVariables['http_referer']);
109 static::assertSame($tags, $assignedVariables['tags']);
110 static::assertArrayHasKey('source', $assignedVariables);
111 static::assertArrayHasKey('default_private_links', $assignedVariables);
112 static::assertArrayHasKey('async_metadata', $assignedVariables);
113 static::assertArrayHasKey('retrieve_description', $assignedVariables);
114 }
115
116 /**
117 * Test displaying bookmark create form without any external metadata retrieval attempt
118 */
119 public function testDisplayCreateFormWithUrlAndWithoutMetadata(): void
120 {
121 $this->container->environment = [
122 'HTTP_REFERER' => $referer = 'http://shaarli/subfolder/controller/?searchtag=abc'
123 ];
124
125 $assignedVariables = [];
126 $this->assignTemplateVars($assignedVariables);
127
128 $url = 'http://url.tld/other?part=3&utm_ad=pay#hash';
129 $expectedUrl = str_replace('&utm_ad=pay', '', $url);
130
131 $request = $this->createMock(Request::class);
132 $request->method('getParam')->willReturnCallback(function (string $key) use ($url): ?string {
133 return $key === 'post' ? $url : null;
134 });
135 $response = new Response();
136
137 $this->container->metadataRetriever->expects(static::never())->method('retrieve');
138
139 $this->container->bookmarkService
140 ->expects(static::once())
141 ->method('bookmarksCountPerTag')
142 ->willReturn($tags = ['tag1' => 2, 'tag2' => 1])
143 ;
144
145 // Make sure that PluginManager hook is triggered
146 $this->container->pluginManager
147 ->expects(static::atLeastOnce())
148 ->method('executeHooks')
149 ->withConsecutive(['render_editlink'], ['render_includes'])
150 ->willReturnCallback(function (string $hook, array $data): array {
151 if ('render_editlink' === $hook) {
152 static::assertSame('', $data['link']['title']);
153 static::assertSame('', $data['link']['description']);
154 }
155
156 return $data;
157 })
158 ;
159
160 $result = $this->controller->displayCreateForm($request, $response);
161
162 static::assertSame(200, $result->getStatusCode());
163 static::assertSame('editlink', (string) $result->getBody());
164
165 static::assertSame('Shaare - Shaarli', $assignedVariables['pagetitle']);
166
167 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
168 static::assertSame('', $assignedVariables['link']['title']);
169 static::assertSame('', $assignedVariables['link']['description']);
170 static::assertSame('', $assignedVariables['link']['tags']);
123 static::assertFalse($assignedVariables['link']['private']); 171 static::assertFalse($assignedVariables['link']['private']);
124 172
125 static::assertTrue($assignedVariables['link_is_new']); 173 static::assertTrue($assignedVariables['link_is_new']);
@@ -127,6 +175,8 @@ class DisplayCreateFormTest extends TestCase
127 static::assertSame($tags, $assignedVariables['tags']); 175 static::assertSame($tags, $assignedVariables['tags']);
128 static::assertArrayHasKey('source', $assignedVariables); 176 static::assertArrayHasKey('source', $assignedVariables);
129 static::assertArrayHasKey('default_private_links', $assignedVariables); 177 static::assertArrayHasKey('default_private_links', $assignedVariables);
178 static::assertArrayHasKey('async_metadata', $assignedVariables);
179 static::assertArrayHasKey('retrieve_description', $assignedVariables);
130 } 180 }
131 181
132 /** 182 /**
@@ -142,7 +192,7 @@ class DisplayCreateFormTest extends TestCase
142 'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash', 192 'post' => 'http://url.tld/other?part=3&utm_ad=pay#hash',
143 'title' => 'Provided Title', 193 'title' => 'Provided Title',
144 'description' => 'Provided description.', 194 'description' => 'Provided description.',
145 'tags' => 'abc def', 195 'tags' => 'abc@def',
146 'private' => '1', 196 'private' => '1',
147 'source' => 'apps', 197 'source' => 'apps',
148 ]; 198 ];
@@ -166,7 +216,7 @@ class DisplayCreateFormTest extends TestCase
166 static::assertSame($expectedUrl, $assignedVariables['link']['url']); 216 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
167 static::assertSame($parameters['title'], $assignedVariables['link']['title']); 217 static::assertSame($parameters['title'], $assignedVariables['link']['title']);
168 static::assertSame($parameters['description'], $assignedVariables['link']['description']); 218 static::assertSame($parameters['description'], $assignedVariables['link']['description']);
169 static::assertSame($parameters['tags'], $assignedVariables['link']['tags']); 219 static::assertSame($parameters['tags'] . '@', $assignedVariables['link']['tags']);
170 static::assertTrue($assignedVariables['link']['private']); 220 static::assertTrue($assignedVariables['link']['private']);
171 static::assertTrue($assignedVariables['link_is_new']); 221 static::assertTrue($assignedVariables['link_is_new']);
172 static::assertSame($parameters['source'], $assignedVariables['source']); 222 static::assertSame($parameters['source'], $assignedVariables['source']);
@@ -310,7 +360,7 @@ class DisplayCreateFormTest extends TestCase
310 static::assertSame($expectedUrl, $assignedVariables['link']['url']); 360 static::assertSame($expectedUrl, $assignedVariables['link']['url']);
311 static::assertSame($title, $assignedVariables['link']['title']); 361 static::assertSame($title, $assignedVariables['link']['title']);
312 static::assertSame($description, $assignedVariables['link']['description']); 362 static::assertSame($description, $assignedVariables['link']['description']);
313 static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); 363 static::assertSame(implode('@', $tags) . '@', $assignedVariables['link']['tags']);
314 static::assertTrue($assignedVariables['link']['private']); 364 static::assertTrue($assignedVariables['link']['private']);
315 static::assertSame($createdAt, $assignedVariables['link']['created']); 365 static::assertSame($createdAt, $assignedVariables['link']['created']);
316 } 366 }
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php b/tests/front/controller/admin/ShaarePublishControllerTest/DisplayEditFormTest.php
index 2dc3f41c..738cea12 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php
+++ b/tests/front/controller/admin/ShaarePublishControllerTest/DisplayEditFormTest.php
@@ -2,12 +2,12 @@
2 2
3declare(strict_types=1); 3declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest; 5namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
6 6
7use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\Exception\BookmarkNotFoundException; 8use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper; 9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
10use Shaarli\Front\Controller\Admin\ManageShaareController; 10use Shaarli\Front\Controller\Admin\ShaarePublishController;
11use Shaarli\Http\HttpAccess; 11use Shaarli\Http\HttpAccess;
12use Shaarli\Security\SessionManager; 12use Shaarli\Security\SessionManager;
13use Shaarli\TestCase; 13use Shaarli\TestCase;
@@ -18,7 +18,7 @@ class DisplayEditFormTest extends TestCase
18{ 18{
19 use FrontAdminControllerMockHelper; 19 use FrontAdminControllerMockHelper;
20 20
21 /** @var ManageShaareController */ 21 /** @var ShaarePublishController */
22 protected $controller; 22 protected $controller;
23 23
24 public function setUp(): void 24 public function setUp(): void
@@ -26,7 +26,7 @@ class DisplayEditFormTest extends TestCase
26 $this->createContainer(); 26 $this->createContainer();
27 27
28 $this->container->httpAccess = $this->createMock(HttpAccess::class); 28 $this->container->httpAccess = $this->createMock(HttpAccess::class);
29 $this->controller = new ManageShaareController($this->container); 29 $this->controller = new ShaarePublishController($this->container);
30 } 30 }
31 31
32 /** 32 /**
@@ -74,7 +74,7 @@ class DisplayEditFormTest extends TestCase
74 static::assertSame($url, $assignedVariables['link']['url']); 74 static::assertSame($url, $assignedVariables['link']['url']);
75 static::assertSame($title, $assignedVariables['link']['title']); 75 static::assertSame($title, $assignedVariables['link']['title']);
76 static::assertSame($description, $assignedVariables['link']['description']); 76 static::assertSame($description, $assignedVariables['link']['description']);
77 static::assertSame(implode(' ', $tags), $assignedVariables['link']['tags']); 77 static::assertSame(implode('@', $tags) . '@', $assignedVariables['link']['tags']);
78 static::assertTrue($assignedVariables['link']['private']); 78 static::assertTrue($assignedVariables['link']['private']);
79 static::assertSame($createdAt, $assignedVariables['link']['created']); 79 static::assertSame($createdAt, $assignedVariables['link']['created']);
80 } 80 }
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php b/tests/front/controller/admin/ShaarePublishControllerTest/SaveBookmarkTest.php
index f7a68226..b6a861bc 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
+++ b/tests/front/controller/admin/ShaarePublishControllerTest/SaveBookmarkTest.php
@@ -2,12 +2,12 @@
2 2
3declare(strict_types=1); 3declare(strict_types=1);
4 4
5namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest; 5namespace Shaarli\Front\Controller\Admin\ShaarePublishControllerTest;
6 6
7use Shaarli\Bookmark\Bookmark; 7use Shaarli\Bookmark\Bookmark;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper; 9use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
10use Shaarli\Front\Controller\Admin\ManageShaareController; 10use Shaarli\Front\Controller\Admin\ShaarePublishController;
11use Shaarli\Front\Exception\WrongTokenException; 11use Shaarli\Front\Exception\WrongTokenException;
12use Shaarli\Http\HttpAccess; 12use Shaarli\Http\HttpAccess;
13use Shaarli\Security\SessionManager; 13use Shaarli\Security\SessionManager;
@@ -20,7 +20,7 @@ class SaveBookmarkTest extends TestCase
20{ 20{
21 use FrontAdminControllerMockHelper; 21 use FrontAdminControllerMockHelper;
22 22
23 /** @var ManageShaareController */ 23 /** @var ShaarePublishController */
24 protected $controller; 24 protected $controller;
25 25
26 public function setUp(): void 26 public function setUp(): void
@@ -28,7 +28,7 @@ class SaveBookmarkTest extends TestCase
28 $this->createContainer(); 28 $this->createContainer();
29 29
30 $this->container->httpAccess = $this->createMock(HttpAccess::class); 30 $this->container->httpAccess = $this->createMock(HttpAccess::class);
31 $this->controller = new ManageShaareController($this->container); 31 $this->controller = new ShaarePublishController($this->container);
32 } 32 }
33 33
34 /** 34 /**
@@ -66,23 +66,27 @@ class SaveBookmarkTest extends TestCase
66 $this->container->bookmarkService 66 $this->container->bookmarkService
67 ->expects(static::once()) 67 ->expects(static::once())
68 ->method('addOrSet') 68 ->method('addOrSet')
69 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { 69 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
70 static::assertFalse($save); 70 static::assertFalse($save);
71 71
72 $checkBookmark($bookmark); 72 $checkBookmark($bookmark);
73 73
74 $bookmark->setId($id); 74 $bookmark->setId($id);
75
76 return $bookmark;
75 }) 77 })
76 ; 78 ;
77 $this->container->bookmarkService 79 $this->container->bookmarkService
78 ->expects(static::once()) 80 ->expects(static::once())
79 ->method('set') 81 ->method('set')
80 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { 82 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
81 static::assertTrue($save); 83 static::assertTrue($save);
82 84
83 $checkBookmark($bookmark); 85 $checkBookmark($bookmark);
84 86
85 static::assertSame($id, $bookmark->getId()); 87 static::assertSame($id, $bookmark->getId());
88
89 return $bookmark;
86 }) 90 })
87 ; 91 ;
88 92
@@ -155,21 +159,25 @@ class SaveBookmarkTest extends TestCase
155 $this->container->bookmarkService 159 $this->container->bookmarkService
156 ->expects(static::once()) 160 ->expects(static::once())
157 ->method('addOrSet') 161 ->method('addOrSet')
158 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { 162 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
159 static::assertFalse($save); 163 static::assertFalse($save);
160 164
161 $checkBookmark($bookmark); 165 $checkBookmark($bookmark);
166
167 return $bookmark;
162 }) 168 })
163 ; 169 ;
164 $this->container->bookmarkService 170 $this->container->bookmarkService
165 ->expects(static::once()) 171 ->expects(static::once())
166 ->method('set') 172 ->method('set')
167 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): void { 173 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($checkBookmark, $id): Bookmark {
168 static::assertTrue($save); 174 static::assertTrue($save);
169 175
170 $checkBookmark($bookmark); 176 $checkBookmark($bookmark);
171 177
172 static::assertSame($id, $bookmark->getId()); 178 static::assertSame($id, $bookmark->getId());
179
180 return $bookmark;
173 }) 181 })
174 ; 182 ;
175 183
@@ -201,7 +209,7 @@ class SaveBookmarkTest extends TestCase
201 /** 209 /**
202 * Test save a bookmark - try to retrieve the thumbnail 210 * Test save a bookmark - try to retrieve the thumbnail
203 */ 211 */
204 public function testSaveBookmarkWithThumbnail(): void 212 public function testSaveBookmarkWithThumbnailSync(): void
205 { 213 {
206 $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash']; 214 $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash'];
207 215
@@ -216,7 +224,13 @@ class SaveBookmarkTest extends TestCase
216 224
217 $this->container->conf = $this->createMock(ConfigManager::class); 225 $this->container->conf = $this->createMock(ConfigManager::class);
218 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) { 226 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
219 return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; 227 if ($key === 'thumbnails.mode') {
228 return Thumbnailer::MODE_ALL;
229 } elseif ($key === 'general.enable_async_metadata') {
230 return false;
231 }
232
233 return $default;
220 }); 234 });
221 235
222 $this->container->thumbnailer = $this->createMock(Thumbnailer::class); 236 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
@@ -230,8 +244,10 @@ class SaveBookmarkTest extends TestCase
230 $this->container->bookmarkService 244 $this->container->bookmarkService
231 ->expects(static::once()) 245 ->expects(static::once())
232 ->method('addOrSet') 246 ->method('addOrSet')
233 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): void { 247 ->willReturnCallback(function (Bookmark $bookmark, bool $save) use ($thumb): Bookmark {
234 static::assertSame($thumb, $bookmark->getThumbnail()); 248 static::assertSame($thumb, $bookmark->getThumbnail());
249
250 return $bookmark;
235 }) 251 })
236 ; 252 ;
237 253
@@ -265,6 +281,51 @@ class SaveBookmarkTest extends TestCase
265 } 281 }
266 282
267 /** 283 /**
284 * Test save a bookmark - do not attempt to retrieve thumbnails if async mode is enabled.
285 */
286 public function testSaveBookmarkWithThumbnailAsync(): void
287 {
288 $parameters = ['lf_url' => 'http://url.tld/other?part=3#hash'];
289
290 $request = $this->createMock(Request::class);
291 $request
292 ->method('getParam')
293 ->willReturnCallback(function (string $key) use ($parameters): ?string {
294 return $parameters[$key] ?? null;
295 })
296 ;
297 $response = new Response();
298
299 $this->container->conf = $this->createMock(ConfigManager::class);
300 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
301 if ($key === 'thumbnails.mode') {
302 return Thumbnailer::MODE_ALL;
303 } elseif ($key === 'general.enable_async_metadata') {
304 return true;
305 }
306
307 return $default;
308 });
309
310 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
311 $this->container->thumbnailer->expects(static::never())->method('get');
312
313 $this->container->bookmarkService
314 ->expects(static::once())
315 ->method('addOrSet')
316 ->willReturnCallback(function (Bookmark $bookmark): Bookmark {
317 static::assertNull($bookmark->getThumbnail());
318
319 return $bookmark;
320 })
321 ;
322
323 $result = $this->controller->save($request, $response);
324
325 static::assertSame(302, $result->getStatusCode());
326 }
327
328 /**
268 * Change the password with a wrong existing password 329 * Change the password with a wrong existing password
269 */ 330 */
270 public function testSaveBookmarkFromBookmarklet(): void 331 public function testSaveBookmarkFromBookmarklet(): void
diff --git a/tests/front/controller/admin/ThumbnailsControllerTest.php b/tests/front/controller/admin/ThumbnailsControllerTest.php
index f4a8acff..e5749654 100644
--- a/tests/front/controller/admin/ThumbnailsControllerTest.php
+++ b/tests/front/controller/admin/ThumbnailsControllerTest.php
@@ -89,8 +89,10 @@ class ThumbnailsControllerTest extends TestCase
89 $this->container->bookmarkService 89 $this->container->bookmarkService
90 ->expects(static::once()) 90 ->expects(static::once())
91 ->method('set') 91 ->method('set')
92 ->willReturnCallback(function (Bookmark $bookmark) use ($thumb) { 92 ->willReturnCallback(function (Bookmark $bookmark) use ($thumb): Bookmark {
93 static::assertSame($thumb, $bookmark->getThumbnail()); 93 static::assertSame($thumb, $bookmark->getThumbnail());
94
95 return $bookmark;
94 }) 96 })
95 ; 97 ;
96 98
diff --git a/tests/front/controller/visitor/BookmarkListControllerTest.php b/tests/front/controller/visitor/BookmarkListControllerTest.php
index 0c95df97..dec938f2 100644
--- a/tests/front/controller/visitor/BookmarkListControllerTest.php
+++ b/tests/front/controller/visitor/BookmarkListControllerTest.php
@@ -173,7 +173,7 @@ class BookmarkListControllerTest extends TestCase
173 $request = $this->createMock(Request::class); 173 $request = $this->createMock(Request::class);
174 $request->method('getParam')->willReturnCallback(function (string $key) { 174 $request->method('getParam')->willReturnCallback(function (string $key) {
175 if ('searchtags' === $key) { 175 if ('searchtags' === $key) {
176 return 'abc def'; 176 return 'abc@def';
177 } 177 }
178 if ('searchterm' === $key) { 178 if ('searchterm' === $key) {
179 return 'ghi jkl'; 179 return 'ghi jkl';
@@ -204,7 +204,7 @@ class BookmarkListControllerTest extends TestCase
204 ->expects(static::once()) 204 ->expects(static::once())
205 ->method('search') 205 ->method('search')
206 ->with( 206 ->with(
207 ['searchtags' => 'abc def', 'searchterm' => 'ghi jkl'], 207 ['searchtags' => 'abc@def', 'searchterm' => 'ghi jkl'],
208 'private', 208 'private',
209 false, 209 false,
210 true 210 true
@@ -222,7 +222,7 @@ class BookmarkListControllerTest extends TestCase
222 static::assertSame('linklist', (string) $result->getBody()); 222 static::assertSame('linklist', (string) $result->getBody());
223 223
224 static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']); 224 static::assertSame('Search: ghi jkl [abc] [def] - Shaarli', $assignedVariables['pagetitle']);
225 static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc+def', $assignedVariables['previous_page_url']); 225 static::assertSame('?page=2&searchterm=ghi+jkl&searchtags=abc%40def', $assignedVariables['previous_page_url']);
226 } 226 }
227 227
228 /** 228 /**
@@ -292,6 +292,37 @@ class BookmarkListControllerTest extends TestCase
292 } 292 }
293 293
294 /** 294 /**
295 * Test GET /shaare/{hash}?key={key} - Find a link by hash using a private link.
296 */
297 public function testPermalinkWithPrivateKey(): void
298 {
299 $hash = 'abcdef';
300 $privateKey = 'this is a private key';
301
302 $assignedVariables = [];
303 $this->assignTemplateVars($assignedVariables);
304
305 $request = $this->createMock(Request::class);
306 $request->method('getParam')->willReturnCallback(function (string $key, $default = null) use ($privateKey) {
307 return $key === 'key' ? $privateKey : $default;
308 });
309 $response = new Response();
310
311 $this->container->bookmarkService
312 ->expects(static::once())
313 ->method('findByHash')
314 ->with($hash, $privateKey)
315 ->willReturn((new Bookmark())->setId(123)->setTitle('Title 1')->setUrl('http://url1.tld'))
316 ;
317
318 $result = $this->controller->permalink($request, $response, ['hash' => $hash]);
319
320 static::assertSame(200, $result->getStatusCode());
321 static::assertSame('linklist', (string) $result->getBody());
322 static::assertCount(1, $assignedVariables['links']);
323 }
324
325 /**
295 * Test getting link list with thumbnail updates. 326 * Test getting link list with thumbnail updates.
296 * -> 2 thumbnails update, only 1 datastore write 327 * -> 2 thumbnails update, only 1 datastore write
297 */ 328 */
@@ -307,7 +338,13 @@ class BookmarkListControllerTest extends TestCase
307 $this->container->conf 338 $this->container->conf
308 ->method('get') 339 ->method('get')
309 ->willReturnCallback(function (string $key, $default) { 340 ->willReturnCallback(function (string $key, $default) {
310 return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; 341 if ($key === 'thumbnails.mode') {
342 return Thumbnailer::MODE_ALL;
343 } elseif ($key === 'general.enable_async_metadata') {
344 return false;
345 }
346
347 return $default;
311 }) 348 })
312 ; 349 ;
313 350
@@ -357,7 +394,13 @@ class BookmarkListControllerTest extends TestCase
357 $this->container->conf 394 $this->container->conf
358 ->method('get') 395 ->method('get')
359 ->willReturnCallback(function (string $key, $default) { 396 ->willReturnCallback(function (string $key, $default) {
360 return $key === 'thumbnails.mode' ? Thumbnailer::MODE_ALL : $default; 397 if ($key === 'thumbnails.mode') {
398 return Thumbnailer::MODE_ALL;
399 } elseif ($key === 'general.enable_async_metadata') {
400 return false;
401 }
402
403 return $default;
361 }) 404 })
362 ; 405 ;
363 406
@@ -379,6 +422,47 @@ class BookmarkListControllerTest extends TestCase
379 } 422 }
380 423
381 /** 424 /**
425 * Test getting a permalink with thumbnail update with async setting: no update should run.
426 */
427 public function testThumbnailUpdateFromPermalinkAsync(): void
428 {
429 $request = $this->createMock(Request::class);
430 $response = new Response();
431
432 $this->container->loginManager = $this->createMock(LoginManager::class);
433 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
434
435 $this->container->conf = $this->createMock(ConfigManager::class);
436 $this->container->conf
437 ->method('get')
438 ->willReturnCallback(function (string $key, $default) {
439 if ($key === 'thumbnails.mode') {
440 return Thumbnailer::MODE_ALL;
441 } elseif ($key === 'general.enable_async_metadata') {
442 return true;
443 }
444
445 return $default;
446 })
447 ;
448
449 $this->container->thumbnailer = $this->createMock(Thumbnailer::class);
450 $this->container->thumbnailer->expects(static::never())->method('get');
451
452 $this->container->bookmarkService
453 ->expects(static::once())
454 ->method('findByHash')
455 ->willReturn((new Bookmark())->setId(2)->setUrl('https://url.tld')->setTitle('Title 1'))
456 ;
457 $this->container->bookmarkService->expects(static::never())->method('set');
458 $this->container->bookmarkService->expects(static::never())->method('save');
459
460 $result = $this->controller->permalink($request, $response, ['hash' => 'abc']);
461
462 static::assertSame(200, $result->getStatusCode());
463 }
464
465 /**
382 * Trigger legacy controller in link list controller: permalink 466 * Trigger legacy controller in link list controller: permalink
383 */ 467 */
384 public function testLegacyControllerPermalink(): void 468 public function testLegacyControllerPermalink(): void
diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php
index fc78bc13..70fbce54 100644
--- a/tests/front/controller/visitor/DailyControllerTest.php
+++ b/tests/front/controller/visitor/DailyControllerTest.php
@@ -28,52 +28,49 @@ class DailyControllerTest extends TestCase
28 public function testValidIndexControllerInvokeDefault(): void 28 public function testValidIndexControllerInvokeDefault(): void
29 { 29 {
30 $currentDay = new \DateTimeImmutable('2020-05-13'); 30 $currentDay = new \DateTimeImmutable('2020-05-13');
31 $previousDate = new \DateTime('2 days ago 00:00:00');
32 $nextDate = new \DateTime('today 00:00:00');
31 33
32 $request = $this->createMock(Request::class); 34 $request = $this->createMock(Request::class);
33 $request->method('getQueryParam')->willReturn($currentDay->format('Ymd')); 35 $request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
36 return $key === 'day' ? $currentDay->format('Ymd') : null;
37 });
34 $response = new Response(); 38 $response = new Response();
35 39
36 // Save RainTPL assigned variables 40 // Save RainTPL assigned variables
37 $assignedVariables = []; 41 $assignedVariables = [];
38 $this->assignTemplateVars($assignedVariables); 42 $this->assignTemplateVars($assignedVariables);
39 43
40 // Links dataset: 2 links with thumbnails
41 $this->container->bookmarkService
42 ->expects(static::once())
43 ->method('days')
44 ->willReturnCallback(function () use ($currentDay): array {
45 return [
46 '20200510',
47 $currentDay->format('Ymd'),
48 '20200516',
49 ];
50 })
51 ;
52 $this->container->bookmarkService 44 $this->container->bookmarkService
53 ->expects(static::once()) 45 ->expects(static::once())
54 ->method('filterDay') 46 ->method('findByDate')
55 ->willReturnCallback(function (): array { 47 ->willReturnCallback(
56 return [ 48 function ($from, $to, &$previous, &$next) use ($currentDay, $previousDate, $nextDate): array {
57 (new Bookmark()) 49 $previous = $previousDate;
58 ->setId(1) 50 $next = $nextDate;
59 ->setUrl('http://url.tld') 51
60 ->setTitle(static::generateString(50)) 52 return [
61 ->setDescription(static::generateString(500)) 53 (new Bookmark())
62 , 54 ->setId(1)
63 (new Bookmark()) 55 ->setUrl('http://url.tld')
64 ->setId(2) 56 ->setTitle(static::generateString(50))
65 ->setUrl('http://url2.tld') 57 ->setDescription(static::generateString(500))
66 ->setTitle(static::generateString(50)) 58 ,
67 ->setDescription(static::generateString(500)) 59 (new Bookmark())
68 , 60 ->setId(2)
69 (new Bookmark()) 61 ->setUrl('http://url2.tld')
70 ->setId(3) 62 ->setTitle(static::generateString(50))
71 ->setUrl('http://url3.tld') 63 ->setDescription(static::generateString(500))
72 ->setTitle(static::generateString(50)) 64 ,
73 ->setDescription(static::generateString(500)) 65 (new Bookmark())
74 , 66 ->setId(3)
75 ]; 67 ->setUrl('http://url3.tld')
76 }) 68 ->setTitle(static::generateString(50))
69 ->setDescription(static::generateString(500))
70 ,
71 ];
72 }
73 )
77 ; 74 ;
78 75
79 // Make sure that PluginManager hook is triggered 76 // Make sure that PluginManager hook is triggered
@@ -81,20 +78,22 @@ class DailyControllerTest extends TestCase
81 ->expects(static::atLeastOnce()) 78 ->expects(static::atLeastOnce())
82 ->method('executeHooks') 79 ->method('executeHooks')
83 ->withConsecutive(['render_daily']) 80 ->withConsecutive(['render_daily'])
84 ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array { 81 ->willReturnCallback(
85 if ('render_daily' === $hook) { 82 function (string $hook, array $data, array $param) use ($currentDay, $previousDate, $nextDate): array {
86 static::assertArrayHasKey('linksToDisplay', $data); 83 if ('render_daily' === $hook) {
87 static::assertCount(3, $data['linksToDisplay']); 84 static::assertArrayHasKey('linksToDisplay', $data);
88 static::assertSame(1, $data['linksToDisplay'][0]['id']); 85 static::assertCount(3, $data['linksToDisplay']);
89 static::assertSame($currentDay->getTimestamp(), $data['day']); 86 static::assertSame(1, $data['linksToDisplay'][0]['id']);
90 static::assertSame('20200510', $data['previousday']); 87 static::assertSame($currentDay->getTimestamp(), $data['day']);
91 static::assertSame('20200516', $data['nextday']); 88 static::assertSame($previousDate->format('Ymd'), $data['previousday']);
92 89 static::assertSame($nextDate->format('Ymd'), $data['nextday']);
93 static::assertArrayHasKey('loggedin', $param); 90
91 static::assertArrayHasKey('loggedin', $param);
92 }
93
94 return $data;
94 } 95 }
95 96 )
96 return $data;
97 })
98 ; 97 ;
99 98
100 $result = $this->controller->index($request, $response); 99 $result = $this->controller->index($request, $response);
@@ -107,6 +106,11 @@ class DailyControllerTest extends TestCase
107 ); 106 );
108 static::assertEquals($currentDay, $assignedVariables['dayDate']); 107 static::assertEquals($currentDay, $assignedVariables['dayDate']);
109 static::assertEquals($currentDay->getTimestamp(), $assignedVariables['day']); 108 static::assertEquals($currentDay->getTimestamp(), $assignedVariables['day']);
109 static::assertSame($previousDate->format('Ymd'), $assignedVariables['previousday']);
110 static::assertSame($nextDate->format('Ymd'), $assignedVariables['nextday']);
111 static::assertSame('day', $assignedVariables['type']);
112 static::assertSame('May 13, 2020', $assignedVariables['dayDesc']);
113 static::assertSame('Daily', $assignedVariables['localizedType']);
110 static::assertCount(3, $assignedVariables['linksToDisplay']); 114 static::assertCount(3, $assignedVariables['linksToDisplay']);
111 115
112 $link = $assignedVariables['linksToDisplay'][0]; 116 $link = $assignedVariables['linksToDisplay'][0];
@@ -171,27 +175,20 @@ class DailyControllerTest extends TestCase
171 $currentDay = new \DateTimeImmutable('2020-05-13'); 175 $currentDay = new \DateTimeImmutable('2020-05-13');
172 176
173 $request = $this->createMock(Request::class); 177 $request = $this->createMock(Request::class);
178 $request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
179 return $key === 'day' ? $currentDay->format('Ymd') : null;
180 });
174 $response = new Response(); 181 $response = new Response();
175 182
176 // Save RainTPL assigned variables 183 // Save RainTPL assigned variables
177 $assignedVariables = []; 184 $assignedVariables = [];
178 $this->assignTemplateVars($assignedVariables); 185 $this->assignTemplateVars($assignedVariables);
179 186
180 // Links dataset: 2 links with thumbnails
181 $this->container->bookmarkService 187 $this->container->bookmarkService
182 ->expects(static::once()) 188 ->expects(static::once())
183 ->method('days') 189 ->method('findByDate')
184 ->willReturnCallback(function () use ($currentDay): array { 190 ->willReturnCallback(function () use ($currentDay): array {
185 return [ 191 return [
186 $currentDay->format($currentDay->format('Ymd')),
187 ];
188 })
189 ;
190 $this->container->bookmarkService
191 ->expects(static::once())
192 ->method('filterDay')
193 ->willReturnCallback(function (): array {
194 return [
195 (new Bookmark()) 192 (new Bookmark())
196 ->setId(1) 193 ->setId(1)
197 ->setUrl('http://url.tld') 194 ->setUrl('http://url.tld')
@@ -250,21 +247,11 @@ class DailyControllerTest extends TestCase
250 $assignedVariables = []; 247 $assignedVariables = [];
251 $this->assignTemplateVars($assignedVariables); 248 $this->assignTemplateVars($assignedVariables);
252 249
253 // Links dataset: 2 links with thumbnails
254 $this->container->bookmarkService 250 $this->container->bookmarkService
255 ->expects(static::once()) 251 ->expects(static::once())
256 ->method('days') 252 ->method('findByDate')
257 ->willReturnCallback(function () use ($currentDay): array { 253 ->willReturnCallback(function () use ($currentDay): array {
258 return [ 254 return [
259 $currentDay->format($currentDay->format('Ymd')),
260 ];
261 })
262 ;
263 $this->container->bookmarkService
264 ->expects(static::once())
265 ->method('filterDay')
266 ->willReturnCallback(function (): array {
267 return [
268 (new Bookmark())->setId(1)->setUrl('http://url.tld')->setTitle('title'), 255 (new Bookmark())->setId(1)->setUrl('http://url.tld')->setTitle('title'),
269 (new Bookmark()) 256 (new Bookmark())
270 ->setId(2) 257 ->setId(2)
@@ -320,14 +307,7 @@ class DailyControllerTest extends TestCase
320 // Links dataset: 2 links with thumbnails 307 // Links dataset: 2 links with thumbnails
321 $this->container->bookmarkService 308 $this->container->bookmarkService
322 ->expects(static::once()) 309 ->expects(static::once())
323 ->method('days') 310 ->method('findByDate')
324 ->willReturnCallback(function (): array {
325 return [];
326 })
327 ;
328 $this->container->bookmarkService
329 ->expects(static::once())
330 ->method('filterDay')
331 ->willReturnCallback(function (): array { 311 ->willReturnCallback(function (): array {
332 return []; 312 return [];
333 }) 313 })
@@ -347,7 +327,7 @@ class DailyControllerTest extends TestCase
347 static::assertSame(200, $result->getStatusCode()); 327 static::assertSame(200, $result->getStatusCode());
348 static::assertSame('daily', (string) $result->getBody()); 328 static::assertSame('daily', (string) $result->getBody());
349 static::assertCount(0, $assignedVariables['linksToDisplay']); 329 static::assertCount(0, $assignedVariables['linksToDisplay']);
350 static::assertSame('Today', $assignedVariables['dayDesc']); 330 static::assertSame('Today - ' . (new \DateTime())->format('F j, Y'), $assignedVariables['dayDesc']);
351 static::assertEquals((new \DateTime())->setTime(0, 0)->getTimestamp(), $assignedVariables['day']); 331 static::assertEquals((new \DateTime())->setTime(0, 0)->getTimestamp(), $assignedVariables['day']);
352 static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']); 332 static::assertEquals((new \DateTime())->setTime(0, 0), $assignedVariables['dayDate']);
353 } 333 }
@@ -361,6 +341,7 @@ class DailyControllerTest extends TestCase
361 new \DateTimeImmutable('2020-05-17'), 341 new \DateTimeImmutable('2020-05-17'),
362 new \DateTimeImmutable('2020-05-15'), 342 new \DateTimeImmutable('2020-05-15'),
363 new \DateTimeImmutable('2020-05-13'), 343 new \DateTimeImmutable('2020-05-13'),
344 new \DateTimeImmutable('+1 month'),
364 ]; 345 ];
365 346
366 $request = $this->createMock(Request::class); 347 $request = $this->createMock(Request::class);
@@ -371,6 +352,7 @@ class DailyControllerTest extends TestCase
371 (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), 352 (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
372 (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), 353 (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
373 (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'), 354 (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'),
355 (new Bookmark())->setId(5)->setCreated($dates[3])->setUrl('http://domain.tld/5'),
374 ]); 356 ]);
375 357
376 $this->container->pageCacheManager 358 $this->container->pageCacheManager
@@ -397,13 +379,14 @@ class DailyControllerTest extends TestCase
397 static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']); 379 static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
398 static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']); 380 static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
399 static::assertFalse($assignedVariables['hide_timestamps']); 381 static::assertFalse($assignedVariables['hide_timestamps']);
400 static::assertCount(2, $assignedVariables['days']); 382 static::assertCount(3, $assignedVariables['days']);
401 383
402 $day = $assignedVariables['days'][$dates[0]->format('Ymd')]; 384 $day = $assignedVariables['days'][$dates[0]->format('Ymd')];
385 $date = $dates[0]->setTime(23, 59, 59);
403 386
404 static::assertEquals($dates[0], $day['date']); 387 static::assertEquals($date, $day['date']);
405 static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']); 388 static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
406 static::assertSame(format_date($dates[0], false), $day['date_human']); 389 static::assertSame(format_date($date, false), $day['date_human']);
407 static::assertSame('http://shaarli/subfolder/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']); 390 static::assertSame('http://shaarli/subfolder/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
408 static::assertCount(1, $day['links']); 391 static::assertCount(1, $day['links']);
409 static::assertSame(1, $day['links'][0]['id']); 392 static::assertSame(1, $day['links'][0]['id']);
@@ -411,10 +394,11 @@ class DailyControllerTest extends TestCase
411 static::assertEquals($dates[0], $day['links'][0]['created']); 394 static::assertEquals($dates[0], $day['links'][0]['created']);
412 395
413 $day = $assignedVariables['days'][$dates[1]->format('Ymd')]; 396 $day = $assignedVariables['days'][$dates[1]->format('Ymd')];
397 $date = $dates[1]->setTime(23, 59, 59);
414 398
415 static::assertEquals($dates[1], $day['date']); 399 static::assertEquals($date, $day['date']);
416 static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']); 400 static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
417 static::assertSame(format_date($dates[1], false), $day['date_human']); 401 static::assertSame(format_date($date, false), $day['date_human']);
418 static::assertSame('http://shaarli/subfolder/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']); 402 static::assertSame('http://shaarli/subfolder/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
419 static::assertCount(2, $day['links']); 403 static::assertCount(2, $day['links']);
420 404
@@ -424,6 +408,18 @@ class DailyControllerTest extends TestCase
424 static::assertSame(3, $day['links'][1]['id']); 408 static::assertSame(3, $day['links'][1]['id']);
425 static::assertSame('http://domain.tld/3', $day['links'][1]['url']); 409 static::assertSame('http://domain.tld/3', $day['links'][1]['url']);
426 static::assertEquals($dates[1], $day['links'][1]['created']); 410 static::assertEquals($dates[1], $day['links'][1]['created']);
411
412 $day = $assignedVariables['days'][$dates[2]->format('Ymd')];
413 $date = $dates[2]->setTime(23, 59, 59);
414
415 static::assertEquals($date, $day['date']);
416 static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
417 static::assertSame(format_date($date, false), $day['date_human']);
418 static::assertSame('http://shaarli/subfolder/daily?day='. $dates[2]->format('Ymd'), $day['absolute_url']);
419 static::assertCount(1, $day['links']);
420 static::assertSame(4, $day['links'][0]['id']);
421 static::assertSame('http://domain.tld/4', $day['links'][0]['url']);
422 static::assertEquals($dates[2], $day['links'][0]['created']);
427 } 423 }
428 424
429 /** 425 /**
@@ -475,4 +471,246 @@ class DailyControllerTest extends TestCase
475 static::assertFalse($assignedVariables['hide_timestamps']); 471 static::assertFalse($assignedVariables['hide_timestamps']);
476 static::assertCount(0, $assignedVariables['days']); 472 static::assertCount(0, $assignedVariables['days']);
477 } 473 }
474
475 /**
476 * Test simple display index with week parameter
477 */
478 public function testSimpleIndexWeekly(): void
479 {
480 $currentDay = new \DateTimeImmutable('2020-05-13');
481 $expectedDay = new \DateTimeImmutable('2020-05-11');
482
483 $request = $this->createMock(Request::class);
484 $request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
485 return $key === 'week' ? $currentDay->format('YW') : null;
486 });
487 $response = new Response();
488
489 // Save RainTPL assigned variables
490 $assignedVariables = [];
491 $this->assignTemplateVars($assignedVariables);
492
493 $this->container->bookmarkService
494 ->expects(static::once())
495 ->method('findByDate')
496 ->willReturnCallback(
497 function (): array {
498 return [
499 (new Bookmark())
500 ->setId(1)
501 ->setUrl('http://url.tld')
502 ->setTitle(static::generateString(50))
503 ->setDescription(static::generateString(500))
504 ,
505 (new Bookmark())
506 ->setId(2)
507 ->setUrl('http://url2.tld')
508 ->setTitle(static::generateString(50))
509 ->setDescription(static::generateString(500))
510 ,
511 ];
512 }
513 )
514 ;
515
516 $result = $this->controller->index($request, $response);
517
518 static::assertSame(200, $result->getStatusCode());
519 static::assertSame('daily', (string) $result->getBody());
520 static::assertSame(
521 'Weekly - Week 20 (May 11, 2020) - Shaarli',
522 $assignedVariables['pagetitle']
523 );
524
525 static::assertCount(2, $assignedVariables['linksToDisplay']);
526 static::assertEquals($expectedDay->setTime(0, 0), $assignedVariables['dayDate']);
527 static::assertSame($expectedDay->setTime(0, 0)->getTimestamp(), $assignedVariables['day']);
528 static::assertSame('', $assignedVariables['previousday']);
529 static::assertSame('', $assignedVariables['nextday']);
530 static::assertSame('Week 20 (May 11, 2020)', $assignedVariables['dayDesc']);
531 static::assertSame('week', $assignedVariables['type']);
532 static::assertSame('Weekly', $assignedVariables['localizedType']);
533 }
534
535 /**
536 * Test simple display index with month parameter
537 */
538 public function testSimpleIndexMonthly(): void
539 {
540 $currentDay = new \DateTimeImmutable('2020-05-13');
541 $expectedDay = new \DateTimeImmutable('2020-05-01');
542
543 $request = $this->createMock(Request::class);
544 $request->method('getQueryParam')->willReturnCallback(function (string $key) use ($currentDay): ?string {
545 return $key === 'month' ? $currentDay->format('Ym') : null;
546 });
547 $response = new Response();
548
549 // Save RainTPL assigned variables
550 $assignedVariables = [];
551 $this->assignTemplateVars($assignedVariables);
552
553 $this->container->bookmarkService
554 ->expects(static::once())
555 ->method('findByDate')
556 ->willReturnCallback(
557 function (): array {
558 return [
559 (new Bookmark())
560 ->setId(1)
561 ->setUrl('http://url.tld')
562 ->setTitle(static::generateString(50))
563 ->setDescription(static::generateString(500))
564 ,
565 (new Bookmark())
566 ->setId(2)
567 ->setUrl('http://url2.tld')
568 ->setTitle(static::generateString(50))
569 ->setDescription(static::generateString(500))
570 ,
571 ];
572 }
573 )
574 ;
575
576 $result = $this->controller->index($request, $response);
577
578 static::assertSame(200, $result->getStatusCode());
579 static::assertSame('daily', (string) $result->getBody());
580 static::assertSame(
581 'Monthly - May, 2020 - Shaarli',
582 $assignedVariables['pagetitle']
583 );
584
585 static::assertCount(2, $assignedVariables['linksToDisplay']);
586 static::assertEquals($expectedDay->setTime(0, 0), $assignedVariables['dayDate']);
587 static::assertSame($expectedDay->setTime(0, 0)->getTimestamp(), $assignedVariables['day']);
588 static::assertSame('', $assignedVariables['previousday']);
589 static::assertSame('', $assignedVariables['nextday']);
590 static::assertSame('May, 2020', $assignedVariables['dayDesc']);
591 static::assertSame('month', $assignedVariables['type']);
592 static::assertSame('Monthly', $assignedVariables['localizedType']);
593 }
594
595 /**
596 * Test simple display RSS with week parameter
597 */
598 public function testSimpleRssWeekly(): void
599 {
600 $dates = [
601 new \DateTimeImmutable('2020-05-19'),
602 new \DateTimeImmutable('2020-05-13'),
603 ];
604 $expectedDates = [
605 new \DateTimeImmutable('2020-05-24 23:59:59'),
606 new \DateTimeImmutable('2020-05-17 23:59:59'),
607 ];
608
609 $this->container->environment['QUERY_STRING'] = 'week';
610 $request = $this->createMock(Request::class);
611 $request->method('getQueryParam')->willReturnCallback(function (string $key): ?string {
612 return $key === 'week' ? '' : null;
613 });
614 $response = new Response();
615
616 $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
617 (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
618 (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
619 (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
620 ]);
621
622 // Save RainTPL assigned variables
623 $assignedVariables = [];
624 $this->assignTemplateVars($assignedVariables);
625
626 $result = $this->controller->rss($request, $response);
627
628 static::assertSame(200, $result->getStatusCode());
629 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
630 static::assertSame('dailyrss', (string) $result->getBody());
631 static::assertSame('Shaarli', $assignedVariables['title']);
632 static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
633 static::assertSame('http://shaarli/subfolder/daily-rss?week', $assignedVariables['page_url']);
634 static::assertFalse($assignedVariables['hide_timestamps']);
635 static::assertCount(2, $assignedVariables['days']);
636
637 $day = $assignedVariables['days'][$dates[0]->format('YW')];
638 $date = $expectedDates[0];
639
640 static::assertEquals($date, $day['date']);
641 static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
642 static::assertSame('Week 21 (May 18, 2020)', $day['date_human']);
643 static::assertSame('http://shaarli/subfolder/daily?week='. $dates[0]->format('YW'), $day['absolute_url']);
644 static::assertCount(1, $day['links']);
645
646 $day = $assignedVariables['days'][$dates[1]->format('YW')];
647 $date = $expectedDates[1];
648
649 static::assertEquals($date, $day['date']);
650 static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
651 static::assertSame('Week 20 (May 11, 2020)', $day['date_human']);
652 static::assertSame('http://shaarli/subfolder/daily?week='. $dates[1]->format('YW'), $day['absolute_url']);
653 static::assertCount(2, $day['links']);
654 }
655
656 /**
657 * Test simple display RSS with month parameter
658 */
659 public function testSimpleRssMonthly(): void
660 {
661 $dates = [
662 new \DateTimeImmutable('2020-05-19'),
663 new \DateTimeImmutable('2020-04-13'),
664 ];
665 $expectedDates = [
666 new \DateTimeImmutable('2020-05-31 23:59:59'),
667 new \DateTimeImmutable('2020-04-30 23:59:59'),
668 ];
669
670 $this->container->environment['QUERY_STRING'] = 'month';
671 $request = $this->createMock(Request::class);
672 $request->method('getQueryParam')->willReturnCallback(function (string $key): ?string {
673 return $key === 'month' ? '' : null;
674 });
675 $response = new Response();
676
677 $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([
678 (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'),
679 (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'),
680 (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'),
681 ]);
682
683 // Save RainTPL assigned variables
684 $assignedVariables = [];
685 $this->assignTemplateVars($assignedVariables);
686
687 $result = $this->controller->rss($request, $response);
688
689 static::assertSame(200, $result->getStatusCode());
690 static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
691 static::assertSame('dailyrss', (string) $result->getBody());
692 static::assertSame('Shaarli', $assignedVariables['title']);
693 static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
694 static::assertSame('http://shaarli/subfolder/daily-rss?month', $assignedVariables['page_url']);
695 static::assertFalse($assignedVariables['hide_timestamps']);
696 static::assertCount(2, $assignedVariables['days']);
697
698 $day = $assignedVariables['days'][$dates[0]->format('Ym')];
699 $date = $expectedDates[0];
700
701 static::assertEquals($date, $day['date']);
702 static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
703 static::assertSame('May, 2020', $day['date_human']);
704 static::assertSame('http://shaarli/subfolder/daily?month='. $dates[0]->format('Ym'), $day['absolute_url']);
705 static::assertCount(1, $day['links']);
706
707 $day = $assignedVariables['days'][$dates[1]->format('Ym')];
708 $date = $expectedDates[1];
709
710 static::assertEquals($date, $day['date']);
711 static::assertSame($date->format(\DateTime::RSS), $day['date_rss']);
712 static::assertSame('April, 2020', $day['date_human']);
713 static::assertSame('http://shaarli/subfolder/daily?month='. $dates[1]->format('Ym'), $day['absolute_url']);
714 static::assertCount(2, $day['links']);
715 }
478} 716}
diff --git a/tests/front/controller/visitor/ErrorControllerTest.php b/tests/front/controller/visitor/ErrorControllerTest.php
index 75408cf4..e18a6fa2 100644
--- a/tests/front/controller/visitor/ErrorControllerTest.php
+++ b/tests/front/controller/visitor/ErrorControllerTest.php
@@ -50,7 +50,31 @@ class ErrorControllerTest extends TestCase
50 } 50 }
51 51
52 /** 52 /**
53 * Test displaying error with any exception (no debug): only display an error occurred with HTTP 500. 53 * Test displaying error with any exception (no debug) while logged in:
54 * display full error details
55 */
56 public function testDisplayAnyExceptionErrorNoDebugLoggedIn(): void
57 {
58 $request = $this->createMock(Request::class);
59 $response = new Response();
60
61 // Save RainTPL assigned variables
62 $assignedVariables = [];
63 $this->assignTemplateVars($assignedVariables);
64
65 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
66
67 $result = ($this->controller)($request, $response, new \Exception('abc'));
68
69 static::assertSame(500, $result->getStatusCode());
70 static::assertSame('Error: abc', $assignedVariables['message']);
71 static::assertContainsPolyfill('Please report it on Github', $assignedVariables['text']);
72 static::assertArrayHasKey('stacktrace', $assignedVariables);
73 }
74
75 /**
76 * Test displaying error with any exception (no debug) while logged out:
77 * display standard error without detail
54 */ 78 */
55 public function testDisplayAnyExceptionErrorNoDebug(): void 79 public function testDisplayAnyExceptionErrorNoDebug(): void
56 { 80 {
@@ -61,10 +85,13 @@ class ErrorControllerTest extends TestCase
61 $assignedVariables = []; 85 $assignedVariables = [];
62 $this->assignTemplateVars($assignedVariables); 86 $this->assignTemplateVars($assignedVariables);
63 87
88 $this->container->loginManager->method('isLoggedIn')->willReturn(false);
89
64 $result = ($this->controller)($request, $response, new \Exception('abc')); 90 $result = ($this->controller)($request, $response, new \Exception('abc'));
65 91
66 static::assertSame(500, $result->getStatusCode()); 92 static::assertSame(500, $result->getStatusCode());
67 static::assertSame('An unexpected error occurred.', $assignedVariables['message']); 93 static::assertSame('An unexpected error occurred.', $assignedVariables['message']);
94 static::assertArrayNotHasKey('text', $assignedVariables);
68 static::assertArrayNotHasKey('stacktrace', $assignedVariables); 95 static::assertArrayNotHasKey('stacktrace', $assignedVariables);
69 } 96 }
70} 97}
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php
index fc0bb7d1..02229f68 100644
--- a/tests/front/controller/visitor/FrontControllerMockHelper.php
+++ b/tests/front/controller/visitor/FrontControllerMockHelper.php
@@ -41,6 +41,10 @@ trait FrontControllerMockHelper
41 // Config 41 // Config
42 $this->container->conf = $this->createMock(ConfigManager::class); 42 $this->container->conf = $this->createMock(ConfigManager::class);
43 $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) { 43 $this->container->conf->method('get')->willReturnCallback(function (string $parameter, $default) {
44 if ($parameter === 'general.tags_separator') {
45 return '@';
46 }
47
44 return $default === null ? $parameter : $default; 48 return $default === null ? $parameter : $default;
45 }); 49 });
46 50
diff --git a/tests/front/controller/visitor/InstallControllerTest.php b/tests/front/controller/visitor/InstallControllerTest.php
index 345ad544..2105ed77 100644
--- a/tests/front/controller/visitor/InstallControllerTest.php
+++ b/tests/front/controller/visitor/InstallControllerTest.php
@@ -79,6 +79,15 @@ class InstallControllerTest extends TestCase
79 static::assertIsArray($assignedVariables['languages']); 79 static::assertIsArray($assignedVariables['languages']);
80 static::assertSame('Automatic', $assignedVariables['languages']['auto']); 80 static::assertSame('Automatic', $assignedVariables['languages']['auto']);
81 static::assertSame('French', $assignedVariables['languages']['fr']); 81 static::assertSame('French', $assignedVariables['languages']['fr']);
82
83 static::assertSame(PHP_VERSION, $assignedVariables['php_version']);
84 static::assertArrayHasKey('php_has_reached_eol', $assignedVariables);
85 static::assertArrayHasKey('php_eol', $assignedVariables);
86 static::assertArrayHasKey('php_extensions', $assignedVariables);
87 static::assertArrayHasKey('permissions', $assignedVariables);
88 static::assertEmpty($assignedVariables['permissions']);
89
90 static::assertSame('Install Shaarli', $assignedVariables['pagetitle']);
82 } 91 }
83 92
84 /** 93 /**
diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php
index 1312ccb7..00d9eab3 100644
--- a/tests/front/controller/visitor/LoginControllerTest.php
+++ b/tests/front/controller/visitor/LoginControllerTest.php
@@ -195,7 +195,7 @@ class LoginControllerTest extends TestCase
195 $this->container->loginManager 195 $this->container->loginManager
196 ->expects(static::once()) 196 ->expects(static::once())
197 ->method('checkCredentials') 197 ->method('checkCredentials')
198 ->with('1.2.3.4', '1.2.3.4', 'bob', 'pass') 198 ->with('1.2.3.4', 'bob', 'pass')
199 ->willReturn(true) 199 ->willReturn(true)
200 ; 200 ;
201 $this->container->loginManager->method('getStaySignedInToken')->willReturn(bin2hex(random_bytes(8))); 201 $this->container->loginManager->method('getStaySignedInToken')->willReturn(bin2hex(random_bytes(8)));
diff --git a/tests/front/controller/visitor/TagCloudControllerTest.php b/tests/front/controller/visitor/TagCloudControllerTest.php
index 9305612e..4915573d 100644
--- a/tests/front/controller/visitor/TagCloudControllerTest.php
+++ b/tests/front/controller/visitor/TagCloudControllerTest.php
@@ -100,7 +100,7 @@ class TagCloudControllerTest extends TestCase
100 ->with() 100 ->with()
101 ->willReturnCallback(function (string $key): ?string { 101 ->willReturnCallback(function (string $key): ?string {
102 if ('searchtags' === $key) { 102 if ('searchtags' === $key) {
103 return 'ghi def'; 103 return 'ghi@def';
104 } 104 }
105 105
106 return null; 106 return null;
@@ -131,7 +131,7 @@ class TagCloudControllerTest extends TestCase
131 ->withConsecutive(['render_tagcloud']) 131 ->withConsecutive(['render_tagcloud'])
132 ->willReturnCallback(function (string $hook, array $data, array $param): array { 132 ->willReturnCallback(function (string $hook, array $data, array $param): array {
133 if ('render_tagcloud' === $hook) { 133 if ('render_tagcloud' === $hook) {
134 static::assertSame('ghi def', $data['search_tags']); 134 static::assertSame('ghi@def@', $data['search_tags']);
135 static::assertCount(1, $data['tags']); 135 static::assertCount(1, $data['tags']);
136 136
137 static::assertArrayHasKey('loggedin', $param); 137 static::assertArrayHasKey('loggedin', $param);
@@ -147,7 +147,7 @@ class TagCloudControllerTest extends TestCase
147 static::assertSame('tag.cloud', (string) $result->getBody()); 147 static::assertSame('tag.cloud', (string) $result->getBody());
148 static::assertSame('ghi def - Tag cloud - Shaarli', $assignedVariables['pagetitle']); 148 static::assertSame('ghi def - Tag cloud - Shaarli', $assignedVariables['pagetitle']);
149 149
150 static::assertSame('ghi def', $assignedVariables['search_tags']); 150 static::assertSame('ghi@def@', $assignedVariables['search_tags']);
151 static::assertCount(1, $assignedVariables['tags']); 151 static::assertCount(1, $assignedVariables['tags']);
152 152
153 static::assertArrayHasKey('abc', $assignedVariables['tags']); 153 static::assertArrayHasKey('abc', $assignedVariables['tags']);
@@ -277,7 +277,7 @@ class TagCloudControllerTest extends TestCase
277 ->with() 277 ->with()
278 ->willReturnCallback(function (string $key): ?string { 278 ->willReturnCallback(function (string $key): ?string {
279 if ('searchtags' === $key) { 279 if ('searchtags' === $key) {
280 return 'ghi def'; 280 return 'ghi@def';
281 } elseif ('sort' === $key) { 281 } elseif ('sort' === $key) {
282 return 'alpha'; 282 return 'alpha';
283 } 283 }
@@ -310,7 +310,7 @@ class TagCloudControllerTest extends TestCase
310 ->withConsecutive(['render_taglist']) 310 ->withConsecutive(['render_taglist'])
311 ->willReturnCallback(function (string $hook, array $data, array $param): array { 311 ->willReturnCallback(function (string $hook, array $data, array $param): array {
312 if ('render_taglist' === $hook) { 312 if ('render_taglist' === $hook) {
313 static::assertSame('ghi def', $data['search_tags']); 313 static::assertSame('ghi@def@', $data['search_tags']);
314 static::assertCount(1, $data['tags']); 314 static::assertCount(1, $data['tags']);
315 315
316 static::assertArrayHasKey('loggedin', $param); 316 static::assertArrayHasKey('loggedin', $param);
@@ -326,7 +326,7 @@ class TagCloudControllerTest extends TestCase
326 static::assertSame('tag.list', (string) $result->getBody()); 326 static::assertSame('tag.list', (string) $result->getBody());
327 static::assertSame('ghi def - Tag list - Shaarli', $assignedVariables['pagetitle']); 327 static::assertSame('ghi def - Tag list - Shaarli', $assignedVariables['pagetitle']);
328 328
329 static::assertSame('ghi def', $assignedVariables['search_tags']); 329 static::assertSame('ghi@def@', $assignedVariables['search_tags']);
330 static::assertCount(1, $assignedVariables['tags']); 330 static::assertCount(1, $assignedVariables['tags']);
331 static::assertSame(3, $assignedVariables['tags']['abc']); 331 static::assertSame(3, $assignedVariables['tags']['abc']);
332 } 332 }
diff --git a/tests/front/controller/visitor/TagControllerTest.php b/tests/front/controller/visitor/TagControllerTest.php
index 750ea02d..5a556c6d 100644
--- a/tests/front/controller/visitor/TagControllerTest.php
+++ b/tests/front/controller/visitor/TagControllerTest.php
@@ -50,7 +50,7 @@ class TagControllerTest extends TestCase
50 50
51 static::assertInstanceOf(Response::class, $result); 51 static::assertInstanceOf(Response::class, $result);
52 static::assertSame(302, $result->getStatusCode()); 52 static::assertSame(302, $result->getStatusCode());
53 static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); 53 static::assertSame(['/controller/?searchtags=def%40abc'], $result->getHeader('location'));
54 } 54 }
55 55
56 public function testAddTagWithoutRefererAndExistingSearch(): void 56 public function testAddTagWithoutRefererAndExistingSearch(): void
@@ -80,7 +80,7 @@ class TagControllerTest extends TestCase
80 80
81 static::assertInstanceOf(Response::class, $result); 81 static::assertInstanceOf(Response::class, $result);
82 static::assertSame(302, $result->getStatusCode()); 82 static::assertSame(302, $result->getStatusCode());
83 static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); 83 static::assertSame(['/controller/?searchtags=def%40abc'], $result->getHeader('location'));
84 } 84 }
85 85
86 public function testAddTagResetPagination(): void 86 public function testAddTagResetPagination(): void
@@ -96,7 +96,7 @@ class TagControllerTest extends TestCase
96 96
97 static::assertInstanceOf(Response::class, $result); 97 static::assertInstanceOf(Response::class, $result);
98 static::assertSame(302, $result->getStatusCode()); 98 static::assertSame(302, $result->getStatusCode());
99 static::assertSame(['/controller/?searchtags=def+abc'], $result->getHeader('location')); 99 static::assertSame(['/controller/?searchtags=def%40abc'], $result->getHeader('location'));
100 } 100 }
101 101
102 public function testAddTagWithRefererAndEmptySearch(): void 102 public function testAddTagWithRefererAndEmptySearch(): void
diff --git a/tests/ApplicationUtilsTest.php b/tests/helper/ApplicationUtilsTest.php
index a232b351..654857b9 100644
--- a/tests/ApplicationUtilsTest.php
+++ b/tests/helper/ApplicationUtilsTest.php
@@ -1,7 +1,8 @@
1<?php 1<?php
2namespace Shaarli; 2namespace Shaarli\Helper;
3 3
4use Shaarli\Config\ConfigManager; 4use Shaarli\Config\ConfigManager;
5use Shaarli\FakeApplicationUtils;
5 6
6require_once 'tests/utils/FakeApplicationUtils.php'; 7require_once 'tests/utils/FakeApplicationUtils.php';
7 8
@@ -340,6 +341,35 @@ class ApplicationUtilsTest extends \Shaarli\TestCase
340 } 341 }
341 342
342 /** 343 /**
344 * Checks resource permissions in minimal mode.
345 */
346 public function testCheckCurrentResourcePermissionsErrorsMinimalMode(): void
347 {
348 $conf = new ConfigManager('');
349 $conf->set('resource.thumbnails_cache', 'null/cache');
350 $conf->set('resource.config', 'null/data/config.php');
351 $conf->set('resource.data_dir', 'null/data');
352 $conf->set('resource.datastore', 'null/data/store.php');
353 $conf->set('resource.ban_file', 'null/data/ipbans.php');
354 $conf->set('resource.log', 'null/data/log.txt');
355 $conf->set('resource.page_cache', 'null/pagecache');
356 $conf->set('resource.raintpl_tmp', 'null/tmp');
357 $conf->set('resource.raintpl_tpl', 'null/tpl');
358 $conf->set('resource.raintpl_theme', 'null/tpl/default');
359 $conf->set('resource.update_check', 'null/data/lastupdatecheck.txt');
360
361 static::assertSame(
362 [
363 '"null/tpl" directory is not readable',
364 '"null/tpl/default" directory is not readable',
365 '"null/tmp" directory is not readable',
366 '"null/tmp" directory is not writable'
367 ],
368 ApplicationUtils::checkResourcePermissions($conf, true)
369 );
370 }
371
372 /**
343 * Check update with 'dev' as curent version (master branch). 373 * Check update with 'dev' as curent version (master branch).
344 * It should always return false. 374 * It should always return false.
345 */ 375 */
@@ -349,4 +379,37 @@ class ApplicationUtilsTest extends \Shaarli\TestCase
349 ApplicationUtils::checkUpdate('dev', self::$testUpdateFile, 100, true, true) 379 ApplicationUtils::checkUpdate('dev', self::$testUpdateFile, 100, true, true)
350 ); 380 );
351 } 381 }
382
383 /**
384 * Basic test of getPhpExtensionsRequirement()
385 */
386 public function testGetPhpExtensionsRequirementSimple(): void
387 {
388 static::assertCount(8, ApplicationUtils::getPhpExtensionsRequirement());
389 static::assertSame([
390 'name' => 'json',
391 'required' => true,
392 'desc' => 'Configuration parsing',
393 'loaded' => true,
394 ], ApplicationUtils::getPhpExtensionsRequirement()[0]);
395 }
396
397 /**
398 * Test getPhpEol with a known version: 7.4 -> 2022
399 */
400 public function testGetKnownPhpEol(): void
401 {
402 static::assertSame('2022-11-28', ApplicationUtils::getPhpEol('7.4.7'));
403 }
404
405 /**
406 * Test getPhpEol with an unknown version: 7.4 -> 2022
407 */
408 public function testGetUnknownPhpEol(): void
409 {
410 static::assertSame(
411 (((int) (new \DateTime())->format('Y')) + 2) . (new \DateTime())->format('-m-d'),
412 ApplicationUtils::getPhpEol('7.51.34')
413 );
414 }
352} 415}
diff --git a/tests/helper/DailyPageHelperTest.php b/tests/helper/DailyPageHelperTest.php
new file mode 100644
index 00000000..5255b7b1
--- /dev/null
+++ b/tests/helper/DailyPageHelperTest.php
@@ -0,0 +1,262 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Helper;
6
7use Shaarli\Bookmark\Bookmark;
8use Shaarli\TestCase;
9use Slim\Http\Request;
10
11class DailyPageHelperTest extends TestCase
12{
13 /**
14 * @dataProvider getRequestedTypes
15 */
16 public function testExtractRequestedType(array $queryParams, string $expectedType): void
17 {
18 $request = $this->createMock(Request::class);
19 $request->method('getQueryParam')->willReturnCallback(function ($key) use ($queryParams): ?string {
20 return $queryParams[$key] ?? null;
21 });
22
23 $type = DailyPageHelper::extractRequestedType($request);
24
25 static::assertSame($type, $expectedType);
26 }
27
28 /**
29 * @dataProvider getRequestedDateTimes
30 */
31 public function testExtractRequestedDateTime(
32 string $type,
33 string $input,
34 ?Bookmark $bookmark,
35 \DateTimeInterface $expectedDateTime,
36 string $compareFormat = 'Ymd'
37 ): void {
38 $dateTime = DailyPageHelper::extractRequestedDateTime($type, $input, $bookmark);
39
40 static::assertSame($dateTime->format($compareFormat), $expectedDateTime->format($compareFormat));
41 }
42
43 public function testExtractRequestedDateTimeExceptionUnknownType(): void
44 {
45 $this->expectException(\Exception::class);
46 $this->expectExceptionMessage('Unsupported daily format type');
47
48 DailyPageHelper::extractRequestedDateTime('nope', null, null);
49 }
50
51 /**
52 * @dataProvider getFormatsByType
53 */
54 public function testGetFormatByType(string $type, string $expectedFormat): void
55 {
56 $format = DailyPageHelper::getFormatByType($type);
57
58 static::assertSame($expectedFormat, $format);
59 }
60
61 public function testGetFormatByTypeExceptionUnknownType(): void
62 {
63 $this->expectException(\Exception::class);
64 $this->expectExceptionMessage('Unsupported daily format type');
65
66 DailyPageHelper::getFormatByType('nope');
67 }
68
69 /**
70 * @dataProvider getStartDatesByType
71 */
72 public function testGetStartDatesByType(
73 string $type,
74 \DateTimeImmutable $dateTime,
75 \DateTimeInterface $expectedDateTime
76 ): void {
77 $startDateTime = DailyPageHelper::getStartDateTimeByType($type, $dateTime);
78
79 static::assertEquals($expectedDateTime, $startDateTime);
80 }
81
82 public function testGetStartDatesByTypeExceptionUnknownType(): void
83 {
84 $this->expectException(\Exception::class);
85 $this->expectExceptionMessage('Unsupported daily format type');
86
87 DailyPageHelper::getStartDateTimeByType('nope', new \DateTimeImmutable());
88 }
89
90 /**
91 * @dataProvider getEndDatesByType
92 */
93 public function testGetEndDatesByType(
94 string $type,
95 \DateTimeImmutable $dateTime,
96 \DateTimeInterface $expectedDateTime
97 ): void {
98 $endDateTime = DailyPageHelper::getEndDateTimeByType($type, $dateTime);
99
100 static::assertEquals($expectedDateTime, $endDateTime);
101 }
102
103 public function testGetEndDatesByTypeExceptionUnknownType(): void
104 {
105 $this->expectException(\Exception::class);
106 $this->expectExceptionMessage('Unsupported daily format type');
107
108 DailyPageHelper::getEndDateTimeByType('nope', new \DateTimeImmutable());
109 }
110
111 /**
112 * @dataProvider getDescriptionsByType
113 */
114 public function testGeDescriptionsByType(
115 string $type,
116 \DateTimeImmutable $dateTime,
117 string $expectedDescription
118 ): void {
119 $description = DailyPageHelper::getDescriptionByType($type, $dateTime);
120
121 static::assertEquals($expectedDescription, $description);
122 }
123
124 public function getDescriptionByTypeExceptionUnknownType(): void
125 {
126 $this->expectException(\Exception::class);
127 $this->expectExceptionMessage('Unsupported daily format type');
128
129 DailyPageHelper::getDescriptionByType('nope', new \DateTimeImmutable());
130 }
131
132 /**
133 * @dataProvider getRssLengthsByType
134 */
135 public function testGeRssLengthsByType(string $type): void {
136 $length = DailyPageHelper::getRssLengthByType($type);
137
138 static::assertIsInt($length);
139 }
140
141 public function testGeRssLengthsByTypeExceptionUnknownType(): void
142 {
143 $this->expectException(\Exception::class);
144 $this->expectExceptionMessage('Unsupported daily format type');
145
146 DailyPageHelper::getRssLengthByType('nope');
147 }
148
149 /**
150 * Data provider for testExtractRequestedType() test method.
151 */
152 public function getRequestedTypes(): array
153 {
154 return [
155 [['month' => null], DailyPageHelper::DAY],
156 [['month' => ''], DailyPageHelper::MONTH],
157 [['month' => 'content'], DailyPageHelper::MONTH],
158 [['week' => null], DailyPageHelper::DAY],
159 [['week' => ''], DailyPageHelper::WEEK],
160 [['week' => 'content'], DailyPageHelper::WEEK],
161 [['day' => null], DailyPageHelper::DAY],
162 [['day' => ''], DailyPageHelper::DAY],
163 [['day' => 'content'], DailyPageHelper::DAY],
164 ];
165 }
166
167 /**
168 * Data provider for testExtractRequestedDateTime() test method.
169 */
170 public function getRequestedDateTimes(): array
171 {
172 return [
173 [DailyPageHelper::DAY, '20201013', null, new \DateTime('2020-10-13')],
174 [
175 DailyPageHelper::DAY,
176 '',
177 (new Bookmark())->setCreated($date = new \DateTime('2020-10-13 12:05:31')),
178 $date,
179 ],
180 [DailyPageHelper::DAY, '', null, new \DateTime()],
181 [DailyPageHelper::WEEK, '202030', null, new \DateTime('2020-07-20')],
182 [
183 DailyPageHelper::WEEK,
184 '',
185 (new Bookmark())->setCreated($date = new \DateTime('2020-10-13 12:05:31')),
186 new \DateTime('2020-10-13'),
187 ],
188 [DailyPageHelper::WEEK, '', null, new \DateTime(), 'Ym'],
189 [DailyPageHelper::MONTH, '202008', null, new \DateTime('2020-08-01'), 'Ym'],
190 [
191 DailyPageHelper::MONTH,
192 '',
193 (new Bookmark())->setCreated($date = new \DateTime('2020-10-13 12:05:31')),
194 new \DateTime('2020-10-13'),
195 'Ym'
196 ],
197 [DailyPageHelper::MONTH, '', null, new \DateTime(), 'Ym'],
198 ];
199 }
200
201 /**
202 * Data provider for testGetFormatByType() test method.
203 */
204 public function getFormatsByType(): array
205 {
206 return [
207 [DailyPageHelper::DAY, 'Ymd'],
208 [DailyPageHelper::WEEK, 'YW'],
209 [DailyPageHelper::MONTH, 'Ym'],
210 ];
211 }
212
213 /**
214 * Data provider for testGetStartDatesByType() test method.
215 */
216 public function getStartDatesByType(): array
217 {
218 return [
219 [DailyPageHelper::DAY, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-09 00:00:00')],
220 [DailyPageHelper::WEEK, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-05 00:00:00')],
221 [DailyPageHelper::MONTH, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-01 00:00:00')],
222 ];
223 }
224
225 /**
226 * Data provider for testGetEndDatesByType() test method.
227 */
228 public function getEndDatesByType(): array
229 {
230 return [
231 [DailyPageHelper::DAY, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-09 23:59:59')],
232 [DailyPageHelper::WEEK, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-11 23:59:59')],
233 [DailyPageHelper::MONTH, new \DateTimeImmutable('2020-10-09 04:05:06'), new \DateTime('2020-10-31 23:59:59')],
234 ];
235 }
236
237 /**
238 * Data provider for testGetDescriptionsByType() test method.
239 */
240 public function getDescriptionsByType(): array
241 {
242 return [
243 [DailyPageHelper::DAY, $date = new \DateTimeImmutable(), 'Today - ' . $date->format('F j, Y')],
244 [DailyPageHelper::DAY, $date = new \DateTimeImmutable('-1 day'), 'Yesterday - ' . $date->format('F j, Y')],
245 [DailyPageHelper::DAY, new \DateTimeImmutable('2020-10-09 04:05:06'), 'October 9, 2020'],
246 [DailyPageHelper::WEEK, new \DateTimeImmutable('2020-10-09 04:05:06'), 'Week 41 (October 5, 2020)'],
247 [DailyPageHelper::MONTH, new \DateTimeImmutable('2020-10-09 04:05:06'), 'October, 2020'],
248 ];
249 }
250
251 /**
252 * Data provider for testGetDescriptionsByType() test method.
253 */
254 public function getRssLengthsByType(): array
255 {
256 return [
257 [DailyPageHelper::DAY],
258 [DailyPageHelper::WEEK],
259 [DailyPageHelper::MONTH],
260 ];
261 }
262}
diff --git a/tests/FileUtilsTest.php b/tests/helper/FileUtilsTest.php
index 9163bdf1..8035f79c 100644
--- a/tests/FileUtilsTest.php
+++ b/tests/helper/FileUtilsTest.php
@@ -1,27 +1,51 @@
1<?php 1<?php
2 2
3namespace Shaarli; 3namespace Shaarli\Helper;
4 4
5use Exception; 5use Exception;
6use Shaarli\Exceptions\IOException;
7use Shaarli\TestCase;
6 8
7/** 9/**
8 * Class FileUtilsTest 10 * Class FileUtilsTest
9 * 11 *
10 * Test file utility class. 12 * Test file utility class.
11 */ 13 */
12class FileUtilsTest extends \Shaarli\TestCase 14class FileUtilsTest extends TestCase
13{ 15{
14 /** 16 /**
15 * @var string Test file path. 17 * @var string Test file path.
16 */ 18 */
17 protected static $file = 'sandbox/flat.db'; 19 protected static $file = 'sandbox/flat.db';
18 20
21 protected function setUp(): void
22 {
23 @mkdir('sandbox');
24 mkdir('sandbox/folder2');
25 touch('sandbox/file1');
26 touch('sandbox/file2');
27 mkdir('sandbox/folder1');
28 touch('sandbox/folder1/file1');
29 touch('sandbox/folder1/file2');
30 mkdir('sandbox/folder3');
31 mkdir('/tmp/shaarli-to-delete');
32 }
33
19 /** 34 /**
20 * Delete test file after every test. 35 * Delete test file after every test.
21 */ 36 */
22 protected function tearDown(): void 37 protected function tearDown(): void
23 { 38 {
24 @unlink(self::$file); 39 @unlink(self::$file);
40
41 @unlink('sandbox/folder1/file1');
42 @unlink('sandbox/folder1/file2');
43 @rmdir('sandbox/folder1');
44 @unlink('sandbox/file1');
45 @unlink('sandbox/file2');
46 @rmdir('sandbox/folder2');
47 @rmdir('sandbox/folder3');
48 @rmdir('/tmp/shaarli-to-delete');
25 } 49 }
26 50
27 /** 51 /**
@@ -107,4 +131,67 @@ class FileUtilsTest extends \Shaarli\TestCase
107 $this->assertEquals(null, FileUtils::readFlatDB(self::$file)); 131 $this->assertEquals(null, FileUtils::readFlatDB(self::$file));
108 $this->assertEquals(['test'], FileUtils::readFlatDB(self::$file, ['test'])); 132 $this->assertEquals(['test'], FileUtils::readFlatDB(self::$file, ['test']));
109 } 133 }
134
135 /**
136 * Test clearFolder with self delete and excluded files
137 */
138 public function testClearFolderSelfDeleteWithExclusion(): void
139 {
140 FileUtils::clearFolder('sandbox', true, ['file2']);
141
142 static::assertFileExists('sandbox/folder1/file2');
143 static::assertFileExists('sandbox/folder1');
144 static::assertFileExists('sandbox/file2');
145 static::assertFileExists('sandbox');
146
147 static::assertFileNotExists('sandbox/folder1/file1');
148 static::assertFileNotExists('sandbox/file1');
149 static::assertFileNotExists('sandbox/folder3');
150 }
151
152 /**
153 * Test clearFolder with self delete and excluded files
154 */
155 public function testClearFolderSelfDeleteWithoutExclusion(): void
156 {
157 FileUtils::clearFolder('sandbox', true);
158
159 static::assertFileNotExists('sandbox');
160 }
161
162 /**
163 * Test clearFolder with self delete and excluded files
164 */
165 public function testClearFolderNoSelfDeleteWithoutExclusion(): void
166 {
167 FileUtils::clearFolder('sandbox', false);
168
169 static::assertFileExists('sandbox');
170
171 // 2 because '.' and '..'
172 static::assertCount(2, new \DirectoryIterator('sandbox'));
173 }
174
175 /**
176 * Test clearFolder on a file instead of a folder
177 */
178 public function testClearFolderOnANonDirectory(): void
179 {
180 $this->expectException(IOException::class);
181 $this->expectExceptionMessage('Provided path is not a directory.');
182
183 FileUtils::clearFolder('sandbox/file1', false);
184 }
185
186 /**
187 * Test clearFolder on a file instead of a folder
188 */
189 public function testClearFolderOutsideOfShaarliDirectory(): void
190 {
191 $this->expectException(IOException::class);
192 $this->expectExceptionMessage('Trying to delete a folder outside of Shaarli path.');
193
194
195 FileUtils::clearFolder('/tmp/shaarli-to-delete', true);
196 }
110} 197}
diff --git a/tests/http/MetadataRetrieverTest.php b/tests/http/MetadataRetrieverTest.php
new file mode 100644
index 00000000..3c9eaa0e
--- /dev/null
+++ b/tests/http/MetadataRetrieverTest.php
@@ -0,0 +1,154 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Http;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Config\ConfigManager;
9
10class MetadataRetrieverTest extends TestCase
11{
12 /** @var MetadataRetriever */
13 protected $retriever;
14
15 /** @var ConfigManager */
16 protected $conf;
17
18 /** @var HttpAccess */
19 protected $httpAccess;
20
21 public function setUp(): void
22 {
23 $this->conf = $this->createMock(ConfigManager::class);
24 $this->httpAccess = $this->createMock(HttpAccess::class);
25 $this->retriever = new MetadataRetriever($this->conf, $this->httpAccess);
26
27 $this->conf->method('get')->willReturnCallback(function (string $param, $default) {
28 return $default === null ? $param : $default;
29 });
30 }
31
32 /**
33 * Test metadata retrieve() with values returned
34 */
35 public function testFullRetrieval(): void
36 {
37 $url = 'https://domain.tld/link';
38 $remoteTitle = 'Remote Title ';
39 $remoteDesc = 'Sometimes the meta description is relevant.';
40 $remoteTags = 'abc def';
41 $remoteCharset = 'utf-8';
42
43 $expectedResult = [
44 'title' => $remoteTitle,
45 'description' => $remoteDesc,
46 'tags' => $remoteTags,
47 ];
48
49 $this->httpAccess
50 ->expects(static::once())
51 ->method('getCurlHeaderCallback')
52 ->willReturnCallback(
53 function (&$charset) use (
54 $remoteCharset
55 ): callable {
56 return function () use (
57 &$charset,
58 $remoteCharset
59 ): void {
60 $charset = $remoteCharset;
61 };
62 }
63 )
64 ;
65 $this->httpAccess
66 ->expects(static::once())
67 ->method('getCurlDownloadCallback')
68 ->willReturnCallback(
69 function (&$charset, &$title, &$description, &$tags) use (
70 $remoteCharset,
71 $remoteTitle,
72 $remoteDesc,
73 $remoteTags
74 ): callable {
75 return function () use (
76 &$charset,
77 &$title,
78 &$description,
79 &$tags,
80 $remoteCharset,
81 $remoteTitle,
82 $remoteDesc,
83 $remoteTags
84 ): void {
85 static::assertSame($remoteCharset, $charset);
86
87 $title = $remoteTitle;
88 $description = $remoteDesc;
89 $tags = $remoteTags;
90 };
91 }
92 )
93 ;
94 $this->httpAccess
95 ->expects(static::once())
96 ->method('getHttpResponse')
97 ->with($url, 30, 4194304)
98 ->willReturnCallback(function($url, $timeout, $maxBytes, $headerCallback, $dlCallback): void {
99 $headerCallback();
100 $dlCallback();
101 })
102 ;
103
104 $result = $this->retriever->retrieve($url);
105
106 static::assertSame($expectedResult, $result);
107 }
108
109 /**
110 * Test metadata retrieve() without any value
111 */
112 public function testEmptyRetrieval(): void
113 {
114 $url = 'https://domain.tld/link';
115
116 $expectedResult = [
117 'title' => null,
118 'description' => null,
119 'tags' => null,
120 ];
121
122 $this->httpAccess
123 ->expects(static::once())
124 ->method('getCurlDownloadCallback')
125 ->willReturnCallback(
126 function (): callable {
127 return function (): void {};
128 }
129 )
130 ;
131 $this->httpAccess
132 ->expects(static::once())
133 ->method('getCurlHeaderCallback')
134 ->willReturnCallback(
135 function (): callable {
136 return function (): void {};
137 }
138 )
139 ;
140 $this->httpAccess
141 ->expects(static::once())
142 ->method('getHttpResponse')
143 ->with($url, 30, 4194304)
144 ->willReturnCallback(function($url, $timeout, $maxBytes, $headerCallback, $dlCallback): void {
145 $headerCallback();
146 $dlCallback();
147 })
148 ;
149
150 $result = $this->retriever->retrieve($url);
151
152 static::assertSame($expectedResult, $result);
153 }
154}
diff --git a/tests/legacy/LegacyLinkDBTest.php b/tests/legacy/LegacyLinkDBTest.php
index df2cad62..5c3fd425 100644
--- a/tests/legacy/LegacyLinkDBTest.php
+++ b/tests/legacy/LegacyLinkDBTest.php
@@ -296,6 +296,10 @@ class LegacyLinkDBTest extends \Shaarli\TestCase
296 // They need to be grouped with the first case found - order by date DESC: `sTuff`. 296 // They need to be grouped with the first case found - order by date DESC: `sTuff`.
297 'sTuff' => 2, 297 'sTuff' => 2,
298 'ut' => 1, 298 'ut' => 1,
299 'assurance' => 1,
300 'coding-style' => 1,
301 'quality' => 1,
302 'standards' => 1,
299 ), 303 ),
300 self::$publicLinkDB->linksCountPerTag() 304 self::$publicLinkDB->linksCountPerTag()
301 ); 305 );
@@ -324,6 +328,10 @@ class LegacyLinkDBTest extends \Shaarli\TestCase
324 'tag3' => 1, 328 'tag3' => 1,
325 'tag4' => 1, 329 'tag4' => 1,
326 'ut' => 1, 330 'ut' => 1,
331 'assurance' => 1,
332 'coding-style' => 1,
333 'quality' => 1,
334 'standards' => 1,
327 ), 335 ),
328 self::$privateLinkDB->linksCountPerTag() 336 self::$privateLinkDB->linksCountPerTag()
329 ); 337 );
@@ -544,6 +552,10 @@ class LegacyLinkDBTest extends \Shaarli\TestCase
544 'tag4' => 1, 552 'tag4' => 1,
545 'ut' => 1, 553 'ut' => 1,
546 'w3c' => 1, 554 'w3c' => 1,
555 'assurance' => 1,
556 'coding-style' => 1,
557 'quality' => 1,
558 'standards' => 1,
547 ]; 559 ];
548 $tags = self::$privateLinkDB->linksCountPerTag(); 560 $tags = self::$privateLinkDB->linksCountPerTag();
549 561
diff --git a/tests/legacy/LegacyUpdaterTest.php b/tests/legacy/LegacyUpdaterTest.php
index f7391b86..395dd4b7 100644
--- a/tests/legacy/LegacyUpdaterTest.php
+++ b/tests/legacy/LegacyUpdaterTest.php
@@ -51,10 +51,10 @@ class LegacyUpdaterTest extends \Shaarli\TestCase
51 */ 51 */
52 public function testReadEmptyUpdatesFile() 52 public function testReadEmptyUpdatesFile()
53 { 53 {
54 $this->assertEquals(array(), UpdaterUtils::read_updates_file('')); 54 $this->assertEquals(array(), UpdaterUtils::readUpdatesFile(''));
55 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; 55 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
56 touch($updatesFile); 56 touch($updatesFile);
57 $this->assertEquals(array(), UpdaterUtils::read_updates_file($updatesFile)); 57 $this->assertEquals(array(), UpdaterUtils::readUpdatesFile($updatesFile));
58 unlink($updatesFile); 58 unlink($updatesFile);
59 } 59 }
60 60
@@ -66,14 +66,14 @@ class LegacyUpdaterTest extends \Shaarli\TestCase
66 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; 66 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
67 $updatesMethods = array('m1', 'm2', 'm3'); 67 $updatesMethods = array('m1', 'm2', 'm3');
68 68
69 UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); 69 UpdaterUtils::writeUpdatesFile($updatesFile, $updatesMethods);
70 $readMethods = UpdaterUtils::read_updates_file($updatesFile); 70 $readMethods = UpdaterUtils::readUpdatesFile($updatesFile);
71 $this->assertEquals($readMethods, $updatesMethods); 71 $this->assertEquals($readMethods, $updatesMethods);
72 72
73 // Update 73 // Update
74 $updatesMethods[] = 'm4'; 74 $updatesMethods[] = 'm4';
75 UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); 75 UpdaterUtils::writeUpdatesFile($updatesFile, $updatesMethods);
76 $readMethods = UpdaterUtils::read_updates_file($updatesFile); 76 $readMethods = UpdaterUtils::readUpdatesFile($updatesFile);
77 $this->assertEquals($readMethods, $updatesMethods); 77 $this->assertEquals($readMethods, $updatesMethods);
78 unlink($updatesFile); 78 unlink($updatesFile);
79 } 79 }
@@ -86,7 +86,7 @@ class LegacyUpdaterTest extends \Shaarli\TestCase
86 $this->expectException(\Exception::class); 86 $this->expectException(\Exception::class);
87 $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/'); 87 $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
88 88
89 UpdaterUtils::write_updates_file('', array('test')); 89 UpdaterUtils::writeUpdatesFile('', array('test'));
90 } 90 }
91 91
92 /** 92 /**
@@ -101,7 +101,7 @@ class LegacyUpdaterTest extends \Shaarli\TestCase
101 touch($updatesFile); 101 touch($updatesFile);
102 chmod($updatesFile, 0444); 102 chmod($updatesFile, 0444);
103 try { 103 try {
104 @UpdaterUtils::write_updates_file($updatesFile, array('test')); 104 @UpdaterUtils::writeUpdatesFile($updatesFile, array('test'));
105 } catch (Exception $e) { 105 } catch (Exception $e) {
106 unlink($updatesFile); 106 unlink($updatesFile);
107 throw $e; 107 throw $e;
diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php
index 9b95ccc9..ad288f78 100644
--- a/tests/netscape/BookmarkExportTest.php
+++ b/tests/netscape/BookmarkExportTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Netscape; 3namespace Shaarli\Netscape;
4 4
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Config\ConfigManager; 7use Shaarli\Config\ConfigManager;
7use Shaarli\Formatter\BookmarkFormatter; 8use Shaarli\Formatter\BookmarkFormatter;
@@ -56,12 +57,13 @@ class BookmarkExportTest extends TestCase
56 */ 57 */
57 public static function setUpBeforeClass(): void 58 public static function setUpBeforeClass(): void
58 { 59 {
60 $mutex = new NoMutex();
59 static::$conf = new ConfigManager('tests/utils/config/configJson'); 61 static::$conf = new ConfigManager('tests/utils/config/configJson');
60 static::$conf->set('resource.datastore', static::$testDatastore); 62 static::$conf->set('resource.datastore', static::$testDatastore);
61 static::$refDb = new \ReferenceLinkDB(); 63 static::$refDb = new \ReferenceLinkDB();
62 static::$refDb->write(static::$testDatastore); 64 static::$refDb->write(static::$testDatastore);
63 static::$history = new History('sandbox/history.php'); 65 static::$history = new History('sandbox/history.php');
64 static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, true); 66 static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, $mutex, true);
65 $factory = new FormatterFactory(static::$conf, true); 67 $factory = new FormatterFactory(static::$conf, true);
66 static::$formatter = $factory->getFormatter('raw'); 68 static::$formatter = $factory->getFormatter('raw');
67 } 69 }
diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php
index c1e49b5f..6856ebca 100644
--- a/tests/netscape/BookmarkImportTest.php
+++ b/tests/netscape/BookmarkImportTest.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Netscape; 3namespace Shaarli\Netscape;
4 4
5use DateTime; 5use DateTime;
6use malkusch\lock\mutex\NoMutex;
6use Psr\Http\Message\UploadedFileInterface; 7use Psr\Http\Message\UploadedFileInterface;
7use Shaarli\Bookmark\Bookmark; 8use Shaarli\Bookmark\Bookmark;
8use Shaarli\Bookmark\BookmarkFileService; 9use Shaarli\Bookmark\BookmarkFileService;
@@ -87,6 +88,7 @@ class BookmarkImportTest extends TestCase
87 */ 88 */
88 protected function setUp(): void 89 protected function setUp(): void
89 { 90 {
91 $mutex = new NoMutex();
90 if (file_exists(self::$testDatastore)) { 92 if (file_exists(self::$testDatastore)) {
91 unlink(self::$testDatastore); 93 unlink(self::$testDatastore);
92 } 94 }
@@ -97,7 +99,7 @@ class BookmarkImportTest extends TestCase
97 $this->conf->set('resource.page_cache', $this->pagecache); 99 $this->conf->set('resource.page_cache', $this->pagecache);
98 $this->conf->set('resource.datastore', self::$testDatastore); 100 $this->conf->set('resource.datastore', self::$testDatastore);
99 $this->history = new History(self::$historyFilePath); 101 $this->history = new History(self::$historyFilePath);
100 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true); 102 $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true);
101 $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history); 103 $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history);
102 } 104 }
103 105
@@ -529,7 +531,7 @@ class BookmarkImportTest extends TestCase
529 { 531 {
530 $post = array( 532 $post = array(
531 'privacy' => 'public', 533 'privacy' => 'public',
532 'default_tags' => 'tag1,tag2 tag3' 534 'default_tags' => 'tag1 tag2 tag3'
533 ); 535 );
534 $files = file2array('netscape_basic.htm'); 536 $files = file2array('netscape_basic.htm');
535 $this->assertStringMatchesFormat( 537 $this->assertStringMatchesFormat(
@@ -550,7 +552,7 @@ class BookmarkImportTest extends TestCase
550 { 552 {
551 $post = array( 553 $post = array(
552 'privacy' => 'public', 554 'privacy' => 'public',
553 'default_tags' => 'tag1&,tag2 "tag3"' 555 'default_tags' => 'tag1& tag2 "tag3"'
554 ); 556 );
555 $files = file2array('netscape_basic.htm'); 557 $files = file2array('netscape_basic.htm');
556 $this->assertStringMatchesFormat( 558 $this->assertStringMatchesFormat(
@@ -571,6 +573,43 @@ class BookmarkImportTest extends TestCase
571 } 573 }
572 574
573 /** 575 /**
576 * Add user-specified tags to all imported bookmarks
577 */
578 public function testSetDefaultTagsWithCustomSeparator()
579 {
580 $separator = '@';
581 $this->conf->set('general.tags_separator', $separator);
582 $post = [
583 'privacy' => 'public',
584 'default_tags' => 'tag1@tag2@tag3@multiple words tag'
585 ];
586 $files = file2array('netscape_basic.htm');
587 $this->assertStringMatchesFormat(
588 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
589 .' 2 bookmarks imported, 0 bookmarks overwritten, 0 bookmarks skipped.',
590 $this->netscapeBookmarkUtils->import($post, $files)
591 );
592 $this->assertEquals(2, $this->bookmarkService->count());
593 $this->assertEquals(0, $this->bookmarkService->count(BookmarkFilter::$PRIVATE));
594 $this->assertEquals(
595 'tag1@tag2@tag3@multiple words tag@private@secret',
596 $this->bookmarkService->get(0)->getTagsString($separator)
597 );
598 $this->assertEquals(
599 ['tag1', 'tag2', 'tag3', 'multiple words tag', 'private', 'secret'],
600 $this->bookmarkService->get(0)->getTags()
601 );
602 $this->assertEquals(
603 'tag1@tag2@tag3@multiple words tag@public@hello@world',
604 $this->bookmarkService->get(1)->getTagsString($separator)
605 );
606 $this->assertEquals(
607 ['tag1', 'tag2', 'tag3', 'multiple words tag', 'public', 'hello', 'world'],
608 $this->bookmarkService->get(1)->getTags()
609 );
610 }
611
612 /**
574 * Ensure each imported bookmark has a unique id 613 * Ensure each imported bookmark has a unique id
575 * 614 *
576 * See https://github.com/shaarli/Shaarli/issues/351 615 * See https://github.com/shaarli/Shaarli/issues/351
diff --git a/tests/plugins/PluginWallabagTest.php b/tests/plugins/PluginWallabagTest.php
index 36317215..9a402fb7 100644
--- a/tests/plugins/PluginWallabagTest.php
+++ b/tests/plugins/PluginWallabagTest.php
@@ -49,14 +49,15 @@ class PluginWallabagTest extends \Shaarli\TestCase
49 $conf = new ConfigManager(''); 49 $conf = new ConfigManager('');
50 $conf->set('plugins.WALLABAG_URL', 'value'); 50 $conf->set('plugins.WALLABAG_URL', 'value');
51 $str = 'http://randomstr.com/test'; 51 $str = 'http://randomstr.com/test';
52 $data = array( 52 $data = [
53 'title' => $str, 53 'title' => $str,
54 'links' => array( 54 'links' => [
55 array( 55 [
56 'url' => $str, 56 'url' => $str,
57 ) 57 ]
58 ) 58 ],
59 ); 59 '_LOGGEDIN_' => true,
60 ];
60 61
61 $data = hook_wallabag_render_linklist($data, $conf); 62 $data = hook_wallabag_render_linklist($data, $conf);
62 $link = $data['links'][0]; 63 $link = $data['links'][0];
@@ -69,4 +70,26 @@ class PluginWallabagTest extends \Shaarli\TestCase
69 $this->assertNotFalse(strpos($link['link_plugin'][0], urlencode($str))); 70 $this->assertNotFalse(strpos($link['link_plugin'][0], urlencode($str)));
70 $this->assertNotFalse(strpos($link['link_plugin'][0], $conf->get('plugins.WALLABAG_URL'))); 71 $this->assertNotFalse(strpos($link['link_plugin'][0], $conf->get('plugins.WALLABAG_URL')));
71 } 72 }
73
74 /**
75 * Test render_linklist hook while logged out: no change.
76 */
77 public function testWallabagLinklistLoggedOut(): void
78 {
79 $conf = new ConfigManager('');
80 $str = 'http://randomstr.com/test';
81 $data = [
82 'title' => $str,
83 'links' => [
84 [
85 'url' => $str,
86 ]
87 ],
88 '_LOGGEDIN_' => false,
89 ];
90
91 $result = hook_wallabag_render_linklist($data, $conf);
92
93 static::assertSame($data, $result);
94 }
72} 95}
diff --git a/tests/security/BanManagerTest.php b/tests/security/BanManagerTest.php
index 698d3d10..29d2791b 100644
--- a/tests/security/BanManagerTest.php
+++ b/tests/security/BanManagerTest.php
@@ -3,7 +3,8 @@
3 3
4namespace Shaarli\Security; 4namespace Shaarli\Security;
5 5
6use Shaarli\FileUtils; 6use Psr\Log\LoggerInterface;
7use Shaarli\Helper\FileUtils;
7use Shaarli\TestCase; 8use Shaarli\TestCase;
8 9
9/** 10/**
@@ -387,7 +388,7 @@ class BanManagerTest extends TestCase
387 3, 388 3,
388 1800, 389 1800,
389 $this->banFile, 390 $this->banFile,
390 $this->logFile 391 $this->createMock(LoggerInterface::class)
391 ); 392 );
392 } 393 }
393} 394}
diff --git a/tests/security/LoginManagerTest.php b/tests/security/LoginManagerTest.php
index d302983d..f7609fc6 100644
--- a/tests/security/LoginManagerTest.php
+++ b/tests/security/LoginManagerTest.php
@@ -2,6 +2,8 @@
2 2
3namespace Shaarli\Security; 3namespace Shaarli\Security;
4 4
5use Psr\Log\LoggerInterface;
6use Shaarli\FakeConfigManager;
5use Shaarli\TestCase; 7use Shaarli\TestCase;
6 8
7/** 9/**
@@ -9,7 +11,7 @@ use Shaarli\TestCase;
9 */ 11 */
10class LoginManagerTest extends TestCase 12class LoginManagerTest extends TestCase
11{ 13{
12 /** @var \FakeConfigManager Configuration Manager instance */ 14 /** @var FakeConfigManager Configuration Manager instance */
13 protected $configManager = null; 15 protected $configManager = null;
14 16
15 /** @var LoginManager Login Manager instance */ 17 /** @var LoginManager Login Manager instance */
@@ -60,6 +62,9 @@ class LoginManagerTest extends TestCase
60 /** @var CookieManager */ 62 /** @var CookieManager */
61 protected $cookieManager; 63 protected $cookieManager;
62 64
65 /** @var BanManager */
66 protected $banManager;
67
63 /** 68 /**
64 * Prepare or reset test resources 69 * Prepare or reset test resources
65 */ 70 */
@@ -71,7 +76,7 @@ class LoginManagerTest extends TestCase
71 76
72 $this->passwordHash = sha1($this->password . $this->login . $this->salt); 77 $this->passwordHash = sha1($this->password . $this->login . $this->salt);
73 78
74 $this->configManager = new \FakeConfigManager([ 79 $this->configManager = new FakeConfigManager([
75 'credentials.login' => $this->login, 80 'credentials.login' => $this->login,
76 'credentials.hash' => $this->passwordHash, 81 'credentials.hash' => $this->passwordHash,
77 'credentials.salt' => $this->salt, 82 'credentials.salt' => $this->salt,
@@ -91,18 +96,29 @@ class LoginManagerTest extends TestCase
91 return $this->cookie[$key] ?? null; 96 return $this->cookie[$key] ?? null;
92 }); 97 });
93 $this->sessionManager = new SessionManager($this->session, $this->configManager, 'session_path'); 98 $this->sessionManager = new SessionManager($this->session, $this->configManager, 'session_path');
94 $this->loginManager = new LoginManager($this->configManager, $this->sessionManager, $this->cookieManager); 99 $this->banManager = $this->createMock(BanManager::class);
100 $this->loginManager = new LoginManager(
101 $this->configManager,
102 $this->sessionManager,
103 $this->cookieManager,
104 $this->banManager,
105 $this->createMock(LoggerInterface::class)
106 );
95 $this->server['REMOTE_ADDR'] = $this->ipAddr; 107 $this->server['REMOTE_ADDR'] = $this->ipAddr;
96 } 108 }
97 109
98 /** 110 /**
99 * Record a failed login attempt 111 * Record a failed login attempt
100 */ 112 */
101 public function testHandleFailedLogin() 113 public function testHandleFailedLogin(): void
102 { 114 {
115 $this->banManager->expects(static::exactly(2))->method('handleFailedAttempt');
116 $this->banManager->method('isBanned')->willReturn(true);
117
103 $this->loginManager->handleFailedLogin($this->server); 118 $this->loginManager->handleFailedLogin($this->server);
104 $this->loginManager->handleFailedLogin($this->server); 119 $this->loginManager->handleFailedLogin($this->server);
105 $this->assertFalse($this->loginManager->canLogin($this->server)); 120
121 static::assertFalse($this->loginManager->canLogin($this->server));
106 } 122 }
107 123
108 /** 124 /**
@@ -114,8 +130,13 @@ class LoginManagerTest extends TestCase
114 'REMOTE_ADDR' => $this->trustedProxy, 130 'REMOTE_ADDR' => $this->trustedProxy,
115 'HTTP_X_FORWARDED_FOR' => $this->ipAddr, 131 'HTTP_X_FORWARDED_FOR' => $this->ipAddr,
116 ]; 132 ];
133
134 $this->banManager->expects(static::exactly(2))->method('handleFailedAttempt');
135 $this->banManager->method('isBanned')->willReturn(true);
136
117 $this->loginManager->handleFailedLogin($server); 137 $this->loginManager->handleFailedLogin($server);
118 $this->loginManager->handleFailedLogin($server); 138 $this->loginManager->handleFailedLogin($server);
139
119 $this->assertFalse($this->loginManager->canLogin($server)); 140 $this->assertFalse($this->loginManager->canLogin($server));
120 } 141 }
121 142
@@ -196,10 +217,16 @@ class LoginManagerTest extends TestCase
196 */ 217 */
197 public function testCheckLoginStateNotConfigured() 218 public function testCheckLoginStateNotConfigured()
198 { 219 {
199 $configManager = new \FakeConfigManager([ 220 $configManager = new FakeConfigManager([
200 'resource.ban_file' => $this->banFile, 221 'resource.ban_file' => $this->banFile,
201 ]); 222 ]);
202 $loginManager = new LoginManager($configManager, null, $this->cookieManager); 223 $loginManager = new LoginManager(
224 $configManager,
225 $this->sessionManager,
226 $this->cookieManager,
227 $this->banManager,
228 $this->createMock(LoggerInterface::class)
229 );
203 $loginManager->checkLoginState(''); 230 $loginManager->checkLoginState('');
204 231
205 $this->assertFalse($loginManager->isLoggedIn()); 232 $this->assertFalse($loginManager->isLoggedIn());
@@ -270,7 +297,7 @@ class LoginManagerTest extends TestCase
270 public function testCheckCredentialsWrongLogin() 297 public function testCheckCredentialsWrongLogin()
271 { 298 {
272 $this->assertFalse( 299 $this->assertFalse(
273 $this->loginManager->checkCredentials('', '', 'b4dl0g1n', $this->password) 300 $this->loginManager->checkCredentials('', 'b4dl0g1n', $this->password)
274 ); 301 );
275 } 302 }
276 303
@@ -280,7 +307,7 @@ class LoginManagerTest extends TestCase
280 public function testCheckCredentialsWrongPassword() 307 public function testCheckCredentialsWrongPassword()
281 { 308 {
282 $this->assertFalse( 309 $this->assertFalse(
283 $this->loginManager->checkCredentials('', '', $this->login, 'b4dp455wd') 310 $this->loginManager->checkCredentials('', $this->login, 'b4dp455wd')
284 ); 311 );
285 } 312 }
286 313
@@ -290,7 +317,7 @@ class LoginManagerTest extends TestCase
290 public function testCheckCredentialsWrongLoginAndPassword() 317 public function testCheckCredentialsWrongLoginAndPassword()
291 { 318 {
292 $this->assertFalse( 319 $this->assertFalse(
293 $this->loginManager->checkCredentials('', '', 'b4dl0g1n', 'b4dp455wd') 320 $this->loginManager->checkCredentials('', 'b4dl0g1n', 'b4dp455wd')
294 ); 321 );
295 } 322 }
296 323
@@ -300,7 +327,7 @@ class LoginManagerTest extends TestCase
300 public function testCheckCredentialsGoodLoginAndPassword() 327 public function testCheckCredentialsGoodLoginAndPassword()
301 { 328 {
302 $this->assertTrue( 329 $this->assertTrue(
303 $this->loginManager->checkCredentials('', '', $this->login, $this->password) 330 $this->loginManager->checkCredentials('', $this->login, $this->password)
304 ); 331 );
305 } 332 }
306 333
@@ -311,7 +338,7 @@ class LoginManagerTest extends TestCase
311 { 338 {
312 $this->configManager->set('ldap.host', 'dummy'); 339 $this->configManager->set('ldap.host', 'dummy');
313 $this->assertFalse( 340 $this->assertFalse(
314 $this->loginManager->checkCredentials('', '', $this->login, $this->password) 341 $this->loginManager->checkCredentials('', $this->login, $this->password)
315 ); 342 );
316 } 343 }
317 344
diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php
index 3f9c3ef5..6830d714 100644
--- a/tests/security/SessionManagerTest.php
+++ b/tests/security/SessionManagerTest.php
@@ -2,6 +2,7 @@
2 2
3namespace Shaarli\Security; 3namespace Shaarli\Security;
4 4
5use Shaarli\FakeConfigManager;
5use Shaarli\TestCase; 6use Shaarli\TestCase;
6 7
7/** 8/**
@@ -12,7 +13,7 @@ class SessionManagerTest extends TestCase
12 /** @var array Session ID hashes */ 13 /** @var array Session ID hashes */
13 protected static $sidHashes = null; 14 protected static $sidHashes = null;
14 15
15 /** @var \FakeConfigManager ConfigManager substitute for testing */ 16 /** @var FakeConfigManager ConfigManager substitute for testing */
16 protected $conf = null; 17 protected $conf = null;
17 18
18 /** @var array $_SESSION array for testing */ 19 /** @var array $_SESSION array for testing */
@@ -34,7 +35,7 @@ class SessionManagerTest extends TestCase
34 */ 35 */
35 protected function setUp(): void 36 protected function setUp(): void
36 { 37 {
37 $this->conf = new \FakeConfigManager([ 38 $this->conf = new FakeConfigManager([
38 'credentials.login' => 'johndoe', 39 'credentials.login' => 'johndoe',
39 'credentials.salt' => 'salt', 40 'credentials.salt' => 'salt',
40 'security.session_protection_disabled' => false, 41 'security.session_protection_disabled' => false,
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index a6280b8c..cadd8265 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -2,6 +2,7 @@
2namespace Shaarli\Updater; 2namespace Shaarli\Updater;
3 3
4use Exception; 4use Exception;
5use malkusch\lock\mutex\NoMutex;
5use Shaarli\Bookmark\BookmarkFileService; 6use Shaarli\Bookmark\BookmarkFileService;
6use Shaarli\Bookmark\BookmarkServiceInterface; 7use Shaarli\Bookmark\BookmarkServiceInterface;
7use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
@@ -44,12 +45,13 @@ class UpdaterTest extends TestCase
44 */ 45 */
45 protected function setUp(): void 46 protected function setUp(): void
46 { 47 {
48 $mutex = new NoMutex();
47 $this->refDB = new \ReferenceLinkDB(); 49 $this->refDB = new \ReferenceLinkDB();
48 $this->refDB->write(self::$testDatastore); 50 $this->refDB->write(self::$testDatastore);
49 51
50 copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php'); 52 copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
51 $this->conf = new ConfigManager(self::$configFile); 53 $this->conf = new ConfigManager(self::$configFile);
52 $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), true); 54 $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), $mutex, true);
53 $this->updater = new Updater([], $this->bookmarkService, $this->conf, true); 55 $this->updater = new Updater([], $this->bookmarkService, $this->conf, true);
54 } 56 }
55 57
@@ -58,10 +60,10 @@ class UpdaterTest extends TestCase
58 */ 60 */
59 public function testReadEmptyUpdatesFile() 61 public function testReadEmptyUpdatesFile()
60 { 62 {
61 $this->assertEquals(array(), UpdaterUtils::read_updates_file('')); 63 $this->assertEquals(array(), UpdaterUtils::readUpdatesFile(''));
62 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; 64 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
63 touch($updatesFile); 65 touch($updatesFile);
64 $this->assertEquals(array(), UpdaterUtils::read_updates_file($updatesFile)); 66 $this->assertEquals(array(), UpdaterUtils::readUpdatesFile($updatesFile));
65 unlink($updatesFile); 67 unlink($updatesFile);
66 } 68 }
67 69
@@ -73,14 +75,14 @@ class UpdaterTest extends TestCase
73 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; 75 $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
74 $updatesMethods = array('m1', 'm2', 'm3'); 76 $updatesMethods = array('m1', 'm2', 'm3');
75 77
76 UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); 78 UpdaterUtils::writeUpdatesFile($updatesFile, $updatesMethods);
77 $readMethods = UpdaterUtils::read_updates_file($updatesFile); 79 $readMethods = UpdaterUtils::readUpdatesFile($updatesFile);
78 $this->assertEquals($readMethods, $updatesMethods); 80 $this->assertEquals($readMethods, $updatesMethods);
79 81
80 // Update 82 // Update
81 $updatesMethods[] = 'm4'; 83 $updatesMethods[] = 'm4';
82 UpdaterUtils::write_updates_file($updatesFile, $updatesMethods); 84 UpdaterUtils::writeUpdatesFile($updatesFile, $updatesMethods);
83 $readMethods = UpdaterUtils::read_updates_file($updatesFile); 85 $readMethods = UpdaterUtils::readUpdatesFile($updatesFile);
84 $this->assertEquals($readMethods, $updatesMethods); 86 $this->assertEquals($readMethods, $updatesMethods);
85 unlink($updatesFile); 87 unlink($updatesFile);
86 } 88 }
@@ -93,7 +95,7 @@ class UpdaterTest extends TestCase
93 $this->expectException(\Exception::class); 95 $this->expectException(\Exception::class);
94 $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/'); 96 $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
95 97
96 UpdaterUtils::write_updates_file('', array('test')); 98 UpdaterUtils::writeUpdatesFile('', array('test'));
97 } 99 }
98 100
99 /** 101 /**
@@ -108,7 +110,7 @@ class UpdaterTest extends TestCase
108 touch($updatesFile); 110 touch($updatesFile);
109 chmod($updatesFile, 0444); 111 chmod($updatesFile, 0444);
110 try { 112 try {
111 @UpdaterUtils::write_updates_file($updatesFile, array('test')); 113 @UpdaterUtils::writeUpdatesFile($updatesFile, array('test'));
112 } catch (Exception $e) { 114 } catch (Exception $e) {
113 unlink($updatesFile); 115 unlink($updatesFile);
114 throw $e; 116 throw $e;
diff --git a/tests/utils/FakeApplicationUtils.php b/tests/utils/FakeApplicationUtils.php
index de83d598..d5289ede 100644
--- a/tests/utils/FakeApplicationUtils.php
+++ b/tests/utils/FakeApplicationUtils.php
@@ -2,6 +2,8 @@
2 2
3namespace Shaarli; 3namespace Shaarli;
4 4
5use Shaarli\Helper\ApplicationUtils;
6
5/** 7/**
6 * Fake ApplicationUtils class to avoid HTTP requests 8 * Fake ApplicationUtils class to avoid HTTP requests
7 */ 9 */
diff --git a/tests/utils/FakeConfigManager.php b/tests/utils/FakeConfigManager.php
index 360b34a9..014c2af0 100644
--- a/tests/utils/FakeConfigManager.php
+++ b/tests/utils/FakeConfigManager.php
@@ -1,9 +1,13 @@
1<?php 1<?php
2 2
3namespace Shaarli;
4
5use Shaarli\Config\ConfigManager;
6
3/** 7/**
4 * Fake ConfigManager 8 * Fake ConfigManager
5 */ 9 */
6class FakeConfigManager 10class FakeConfigManager extends ConfigManager
7{ 11{
8 protected $values = []; 12 protected $values = [];
9 13
@@ -23,7 +27,7 @@ class FakeConfigManager
23 * @param string $key Key of the value to set 27 * @param string $key Key of the value to set
24 * @param mixed $value Value to set 28 * @param mixed $value Value to set
25 */ 29 */
26 public function set($key, $value) 30 public function set($key, $value, $write = false, $isLoggedIn = false)
27 { 31 {
28 $this->values[$key] = $value; 32 $this->values[$key] = $value;
29 } 33 }
@@ -35,7 +39,7 @@ class FakeConfigManager
35 * 39 *
36 * @return mixed The value if set, else the name of the key 40 * @return mixed The value if set, else the name of the key
37 */ 41 */
38 public function get($key) 42 public function get($key, $default = '')
39 { 43 {
40 if (isset($this->values[$key])) { 44 if (isset($this->values[$key])) {
41 return $this->values[$key]; 45 return $this->values[$key];
diff --git a/tests/utils/ReferenceHistory.php b/tests/utils/ReferenceHistory.php
index 516c9f51..aed5d2cf 100644
--- a/tests/utils/ReferenceHistory.php
+++ b/tests/utils/ReferenceHistory.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2 2
3use Shaarli\FileUtils; 3use Shaarli\Helper\FileUtils;
4use Shaarli\History; 4use Shaarli\History;
5 5
6/** 6/**
diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php
index fc3cb109..1f53dc3c 100644
--- a/tests/utils/ReferenceLinkDB.php
+++ b/tests/utils/ReferenceLinkDB.php
@@ -82,7 +82,7 @@ class ReferenceLinkDB
82 'This guide extends and expands on PSR-1, the basic coding standard.', 82 'This guide extends and expands on PSR-1, the basic coding standard.',
83 0, 83 0,
84 DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_152312'), 84 DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20121206_152312'),
85 '' 85 'coding-style standards quality assurance'
86 ); 86 );
87 87
88 $this->addLink( 88 $this->addLink(