aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/ApplicationUtilsTest.php55
-rw-r--r--tests/FeedBuilderTest.php14
-rw-r--r--tests/FileUtilsTest.php108
-rw-r--r--tests/HistoryTest.php207
-rw-r--r--tests/HttpUtils/IsHttpsTest.php36
-rw-r--r--tests/HttpUtils/ServerUrlTest.php73
-rw-r--r--tests/LanguagesTest.php186
-rw-r--r--tests/LinkDBTest.php90
-rw-r--r--tests/LinkFilterTest.php102
-rw-r--r--tests/LinkUtilsTest.php269
-rw-r--r--tests/NetscapeBookmarkUtils/BookmarkImportTest.php144
-rw-r--r--tests/PluginManagerTest.php1
-rw-r--r--tests/SessionManagerTest.php149
-rw-r--r--tests/ThemeUtilsTest.php55
-rw-r--r--tests/TimeZoneTest.php83
-rw-r--r--tests/Updater/UpdaterTest.php187
-rw-r--r--tests/Url/CleanupUrlTest.php102
-rw-r--r--tests/Url/UrlTest.php8
-rw-r--r--tests/Url/WhitelistProtocolsTest.php63
-rw-r--r--tests/UtilsTest.php286
-rw-r--r--tests/api/ApiMiddlewareTest.php208
-rw-r--r--tests/api/ApiUtilsTest.php352
-rw-r--r--tests/api/controllers/DeleteLinkTest.php126
-rw-r--r--tests/api/controllers/GetLinkIdTest.php132
-rw-r--r--tests/api/controllers/GetLinksTest.php472
-rw-r--r--tests/api/controllers/HistoryTest.php216
-rw-r--r--tests/api/controllers/InfoTest.php115
-rw-r--r--tests/api/controllers/PostLinkTest.php216
-rw-r--r--tests/api/controllers/PutLinkTest.php222
-rw-r--r--tests/bootstrap.php6
-rw-r--r--tests/config/ConfigJsonTest.php13
-rw-r--r--tests/config/ConfigManagerTest.php9
-rw-r--r--tests/config/ConfigPhpTest.php19
-rw-r--r--tests/config/ConfigPluginTest.php10
-rw-r--r--tests/docker/alpine36/Dockerfile34
-rw-r--r--tests/docker/debian8/Dockerfile35
-rw-r--r--tests/docker/debian9/Dockerfile36
-rw-r--r--tests/docker/ubuntu16/Dockerfile36
-rw-r--r--tests/languages/bootstrap.php6
-rw-r--r--tests/languages/de/UtilsDeTest.php119
-rw-r--r--tests/languages/en/UtilsEnTest.php119
-rw-r--r--tests/languages/fr/LanguagesFrTest.php175
-rw-r--r--tests/languages/fr/UtilsFrTest.php119
-rw-r--r--tests/plugins/PluginAddlinkTest.php46
-rw-r--r--tests/plugins/PluginArchiveorgTest.php10
-rw-r--r--tests/plugins/PluginIssoTest.php15
-rw-r--r--tests/plugins/PluginMarkdownTest.php30
-rw-r--r--tests/plugins/PluginPlayvideosTest.php6
-rw-r--r--tests/plugins/PluginPubsubhubbubTest.php55
-rw-r--r--tests/plugins/PluginQrcodeTest.php (renamed from tests/plugins/PlugQrcodeTest.php)13
-rw-r--r--tests/plugins/PluginReadityourselfTest.php98
-rw-r--r--tests/plugins/PluginWallabagTest.php9
-rw-r--r--tests/plugins/WallabagInstanceTest.php8
-rw-r--r--tests/plugins/resources/markdown.html11
-rw-r--r--tests/plugins/resources/markdown.md12
-rw-r--r--tests/utils/FakeConfigManager.php12
-rw-r--r--tests/utils/ReferenceHistory.php82
-rw-r--r--tests/utils/ReferenceLinkDB.php51
-rw-r--r--tests/utils/config/configJson.json.php3
-rw-r--r--tests/utils/config/emptyConfigPhp.php1
-rw-r--r--tests/utils/languages/fr/LC_MESSAGES/test.mobin0 -> 456 bytes
-rw-r--r--tests/utils/languages/fr/LC_MESSAGES/test.po19
62 files changed, 5053 insertions, 441 deletions
diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php
index 4a0975bf..ff4c9e17 100644
--- a/tests/ApplicationUtilsTest.php
+++ b/tests/ApplicationUtilsTest.php
@@ -1,9 +1,10 @@
1<?php 1<?php
2use Shaarli\Config\ConfigManager;
3
2/** 4/**
3 * ApplicationUtils' tests 5 * ApplicationUtils' tests
4 */ 6 */
5 7
6require_once 'application/config/ConfigManager.php';
7require_once 'application/ApplicationUtils.php'; 8require_once 'application/ApplicationUtils.php';
8 9
9/** 10/**
@@ -16,7 +17,7 @@ class FakeApplicationUtils extends ApplicationUtils
16 /** 17 /**
17 * Toggle HTTP requests, allow overriding the version code 18 * Toggle HTTP requests, allow overriding the version code
18 */ 19 */
19 public static function getLatestGitVersionCode($url, $timeout=0) 20 public static function getVersion($url, $timeout=0)
20 { 21 {
21 return self::$VERSION_CODE; 22 return self::$VERSION_CODE;
22 } 23 }
@@ -44,17 +45,27 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
44 } 45 }
45 46
46 /** 47 /**
48 * Remove test version file if it exists
49 */
50 public function tearDown()
51 {
52 if (is_file('sandbox/version.php')) {
53 unlink('sandbox/version.php');
54 }
55 }
56
57 /**
47 * Retrieve the latest version code available on Git 58 * Retrieve the latest version code available on Git
48 * 59 *
49 * Expected format: Semantic Versioning - major.minor.patch 60 * Expected format: Semantic Versioning - major.minor.patch
50 */ 61 */
51 public function testGetLatestGitVersionCode() 62 public function testGetVersionCode()
52 { 63 {
53 $testTimeout = 10; 64 $testTimeout = 10;
54 65
55 $this->assertEquals( 66 $this->assertEquals(
56 '0.5.4', 67 '0.5.4',
57 ApplicationUtils::getLatestGitVersionCode( 68 ApplicationUtils::getVersion(
58 'https://raw.githubusercontent.com/shaarli/Shaarli/' 69 'https://raw.githubusercontent.com/shaarli/Shaarli/'
59 .'v0.5.4/shaarli_version.php', 70 .'v0.5.4/shaarli_version.php',
60 $testTimeout 71 $testTimeout
@@ -62,23 +73,35 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
62 ); 73 );
63 $this->assertRegExp( 74 $this->assertRegExp(
64 self::$versionPattern, 75 self::$versionPattern,
65 ApplicationUtils::getLatestGitVersionCode( 76 ApplicationUtils::getVersion(
66 'https://raw.githubusercontent.com/shaarli/Shaarli/' 77 'https://raw.githubusercontent.com/shaarli/Shaarli/'
67 .'stable/shaarli_version.php', 78 .'latest/shaarli_version.php',
68 $testTimeout 79 $testTimeout
69 ) 80 )
70 ); 81 );
71 } 82 }
72 83
73 /** 84 /**
74 * Attempt to retrieve the latest version from an invalid URL 85 * Attempt to retrieve the latest version from an invalid File
75 */ 86 */
76 public function testGetLatestGitVersionCodeInvalidUrl() 87 public function testGetVersionCodeFromFile()
88 {
89 file_put_contents('sandbox/version.php', '<?php /* 1.2.3 */ ?>'. PHP_EOL);
90 $this->assertEquals(
91 '1.2.3',
92 ApplicationUtils::getVersion('sandbox/version.php', 1)
93 );
94 }
95
96 /**
97 * Attempt to retrieve the latest version from an invalid File
98 */
99 public function testGetVersionCodeInvalidFile()
77 { 100 {
78 $oldlog = ini_get('error_log'); 101 $oldlog = ini_get('error_log');
79 ini_set('error_log', '/dev/null'); 102 ini_set('error_log', '/dev/null');
80 $this->assertFalse( 103 $this->assertFalse(
81 ApplicationUtils::getLatestGitVersionCode('htttp://null.io', 1) 104 ApplicationUtils::getVersion('idontexist', 1)
82 ); 105 );
83 ini_set('error_log', $oldlog); 106 ini_set('error_log', $oldlog);
84 } 107 }
@@ -289,6 +312,7 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
289 $conf->set('resource.page_cache', 'pagecache'); 312 $conf->set('resource.page_cache', 'pagecache');
290 $conf->set('resource.raintpl_tmp', 'tmp'); 313 $conf->set('resource.raintpl_tmp', 'tmp');
291 $conf->set('resource.raintpl_tpl', 'tpl'); 314 $conf->set('resource.raintpl_tpl', 'tpl');
315 $conf->set('resource.theme', 'default');
292 $conf->set('resource.update_check', 'data/lastupdatecheck.txt'); 316 $conf->set('resource.update_check', 'data/lastupdatecheck.txt');
293 317
294 $this->assertEquals( 318 $this->assertEquals(
@@ -312,10 +336,12 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
312 $conf->set('resource.page_cache', 'null/pagecache'); 336 $conf->set('resource.page_cache', 'null/pagecache');
313 $conf->set('resource.raintpl_tmp', 'null/tmp'); 337 $conf->set('resource.raintpl_tmp', 'null/tmp');
314 $conf->set('resource.raintpl_tpl', 'null/tpl'); 338 $conf->set('resource.raintpl_tpl', 'null/tpl');
339 $conf->set('resource.raintpl_theme', 'null/tpl/default');
315 $conf->set('resource.update_check', 'null/data/lastupdatecheck.txt'); 340 $conf->set('resource.update_check', 'null/data/lastupdatecheck.txt');
316 $this->assertEquals( 341 $this->assertEquals(
317 array( 342 array(
318 '"null/tpl" directory is not readable', 343 '"null/tpl" directory is not readable',
344 '"null/tpl/default" directory is not readable',
319 '"null/cache" directory is not readable', 345 '"null/cache" directory is not readable',
320 '"null/cache" directory is not writable', 346 '"null/cache" directory is not writable',
321 '"null/data" directory is not readable', 347 '"null/data" directory is not readable',
@@ -328,4 +354,15 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase
328 ApplicationUtils::checkResourcePermissions($conf) 354 ApplicationUtils::checkResourcePermissions($conf)
329 ); 355 );
330 } 356 }
357
358 /**
359 * Check update with 'dev' as curent version (master branch).
360 * It should always return false.
361 */
362 public function testCheckUpdateDev()
363 {
364 $this->assertFalse(
365 ApplicationUtils::checkUpdate('dev', self::$testUpdateFile, 100, true, true)
366 );
367 }
331} 368}
diff --git a/tests/FeedBuilderTest.php b/tests/FeedBuilderTest.php
index 06a44506..a590306d 100644
--- a/tests/FeedBuilderTest.php
+++ b/tests/FeedBuilderTest.php
@@ -75,7 +75,6 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
75 $data = $feedBuilder->buildData(); 75 $data = $feedBuilder->buildData();
76 // Test headers (RSS) 76 // Test headers (RSS)
77 $this->assertEquals(self::$RSS_LANGUAGE, $data['language']); 77 $this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
78 $this->assertEmpty($data['pubsubhub_url']);
79 $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']); 78 $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']);
80 $this->assertEquals(true, $data['show_dates']); 79 $this->assertEquals(true, $data['show_dates']);
81 $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']); 80 $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']);
@@ -211,19 +210,6 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
211 } 210 }
212 211
213 /** 212 /**
214 * Test buildData with hide dates settings.
215 */
216 public function testBuildDataPubsubhub()
217 {
218 $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, null, false);
219 $feedBuilder->setLocale(self::$LOCALE);
220 $feedBuilder->setPubsubhubUrl('http://pubsubhub.io');
221 $data = $feedBuilder->buildData();
222 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
223 $this->assertEquals('http://pubsubhub.io', $data['pubsubhub_url']);
224 }
225
226 /**
227 * Test buildData when Shaarli is served from a subdirectory 213 * Test buildData when Shaarli is served from a subdirectory
228 */ 214 */
229 public function testBuildDataServerSubdir() 215 public function testBuildDataServerSubdir()
diff --git a/tests/FileUtilsTest.php b/tests/FileUtilsTest.php
new file mode 100644
index 00000000..d764e495
--- /dev/null
+++ b/tests/FileUtilsTest.php
@@ -0,0 +1,108 @@
1<?php
2
3require_once 'application/FileUtils.php';
4
5/**
6 * Class FileUtilsTest
7 *
8 * Test file utility class.
9 */
10class FileUtilsTest extends PHPUnit_Framework_TestCase
11{
12 /**
13 * @var string Test file path.
14 */
15 protected static $file = 'sandbox/flat.db';
16
17 /**
18 * Delete test file after every test.
19 */
20 public function tearDown()
21 {
22 @unlink(self::$file);
23 }
24
25 /**
26 * Test writeDB, then readDB with different data.
27 */
28 public function testSimpleWriteRead()
29 {
30 $data = ['blue', 'red'];
31 $this->assertTrue(FileUtils::writeFlatDB(self::$file, $data) > 0);
32 $this->assertTrue(startsWith(file_get_contents(self::$file), '<?php /*'));
33 $this->assertEquals($data, FileUtils::readFlatDB(self::$file));
34
35 $data = 0;
36 $this->assertTrue(FileUtils::writeFlatDB(self::$file, $data) > 0);
37 $this->assertEquals($data, FileUtils::readFlatDB(self::$file));
38
39 $data = null;
40 $this->assertTrue(FileUtils::writeFlatDB(self::$file, $data) > 0);
41 $this->assertEquals($data, FileUtils::readFlatDB(self::$file));
42
43 $data = false;
44 $this->assertTrue(FileUtils::writeFlatDB(self::$file, $data) > 0);
45 $this->assertEquals($data, FileUtils::readFlatDB(self::$file));
46 }
47
48 /**
49 * File not writable: raise an exception.
50 *
51 * @expectedException IOException
52 * @expectedExceptionMessage Error accessing "sandbox/flat.db"
53 */
54 public function testWriteWithoutPermission()
55 {
56 touch(self::$file);
57 chmod(self::$file, 0440);
58 FileUtils::writeFlatDB(self::$file, null);
59 }
60
61 /**
62 * Folder non existent: raise an exception.
63 *
64 * @expectedException IOException
65 * @expectedExceptionMessage Error accessing "nopefolder"
66 */
67 public function testWriteFolderDoesNotExist()
68 {
69 FileUtils::writeFlatDB('nopefolder/file', null);
70 }
71
72 /**
73 * Folder non writable: raise an exception.
74 *
75 * @expectedException IOException
76 * @expectedExceptionMessage Error accessing "sandbox"
77 */
78 public function testWriteFolderPermission()
79 {
80 chmod(dirname(self::$file), 0555);
81 try {
82 FileUtils::writeFlatDB(self::$file, null);
83 } catch (Exception $e) {
84 chmod(dirname(self::$file), 0755);
85 throw $e;
86 }
87 }
88
89 /**
90 * Read non existent file, use default parameter.
91 */
92 public function testReadNotExistentFile()
93 {
94 $this->assertEquals(null, FileUtils::readFlatDB(self::$file));
95 $this->assertEquals(['test'], FileUtils::readFlatDB(self::$file, ['test']));
96 }
97
98 /**
99 * Read non readable file, use default parameter.
100 */
101 public function testReadNotReadable()
102 {
103 touch(self::$file);
104 chmod(self::$file, 0220);
105 $this->assertEquals(null, FileUtils::readFlatDB(self::$file));
106 $this->assertEquals(['test'], FileUtils::readFlatDB(self::$file, ['test']));
107 }
108}
diff --git a/tests/HistoryTest.php b/tests/HistoryTest.php
new file mode 100644
index 00000000..d3bef5a3
--- /dev/null
+++ b/tests/HistoryTest.php
@@ -0,0 +1,207 @@
1<?php
2
3require_once 'application/History.php';
4
5
6class HistoryTest extends PHPUnit_Framework_TestCase
7{
8 /**
9 * @var string History file path
10 */
11 protected static $historyFilePath = 'sandbox/history.php';
12
13 /**
14 * Delete history file.
15 */
16 public function tearDown()
17 {
18 @unlink(self::$historyFilePath);
19 }
20
21 /**
22 * Test that the history file is created if it doesn't exist.
23 */
24 public function testConstructLazyLoading()
25 {
26 new History(self::$historyFilePath);
27 $this->assertFileNotExists(self::$historyFilePath);
28 }
29
30 /**
31 * Test that the history file is created if it doesn't exist.
32 */
33 public function testAddEventCreateFile()
34 {
35 $history = new History(self::$historyFilePath);
36 $history->updateSettings();
37 $this->assertFileExists(self::$historyFilePath);
38 }
39
40 /**
41 * Not writable history file: raise an exception.
42 *
43 * @expectedException Exception
44 * @expectedExceptionMessage History file isn't readable or writable
45 */
46 public function testConstructNotWritable()
47 {
48 touch(self::$historyFilePath);
49 chmod(self::$historyFilePath, 0440);
50 $history = new History(self::$historyFilePath);
51 $history->updateSettings();
52 }
53
54 /**
55 * Not parsable history file: raise an exception.
56 *
57 * @expectedException Exception
58 * @expectedExceptionMessageRegExp /Could not parse history file/
59 */
60 public function testConstructNotParsable()
61 {
62 file_put_contents(self::$historyFilePath, 'not parsable');
63 $history = new History(self::$historyFilePath);
64 // gzinflate generates a warning
65 @$history->updateSettings();
66 }
67
68 /**
69 * Test add link event
70 */
71 public function testAddLink()
72 {
73 $history = new History(self::$historyFilePath);
74 $history->addLink(['id' => 0]);
75 $actual = $history->getHistory()[0];
76 $this->assertEquals(History::CREATED, $actual['event']);
77 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
78 $this->assertEquals(0, $actual['id']);
79
80 $history = new History(self::$historyFilePath);
81 $history->addLink(['id' => 1]);
82 $actual = $history->getHistory()[0];
83 $this->assertEquals(History::CREATED, $actual['event']);
84 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
85 $this->assertEquals(1, $actual['id']);
86
87 $history = new History(self::$historyFilePath);
88 $history->addLink(['id' => 'str']);
89 $actual = $history->getHistory()[0];
90 $this->assertEquals(History::CREATED, $actual['event']);
91 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
92 $this->assertEquals('str', $actual['id']);
93 }
94
95 /**
96 * Test updated link event
97 */
98 public function testUpdateLink()
99 {
100 $history = new History(self::$historyFilePath);
101 $history->updateLink(['id' => 1]);
102 $actual = $history->getHistory()[0];
103 $this->assertEquals(History::UPDATED, $actual['event']);
104 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
105 $this->assertEquals(1, $actual['id']);
106 }
107
108 /**
109 * Test delete link event
110 */
111 public function testDeleteLink()
112 {
113 $history = new History(self::$historyFilePath);
114 $history->deleteLink(['id' => 1]);
115 $actual = $history->getHistory()[0];
116 $this->assertEquals(History::DELETED, $actual['event']);
117 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
118 $this->assertEquals(1, $actual['id']);
119 }
120
121 /**
122 * Test updated settings event
123 */
124 public function testUpdateSettings()
125 {
126 $history = new History(self::$historyFilePath);
127 $history->updateSettings();
128 $actual = $history->getHistory()[0];
129 $this->assertEquals(History::SETTINGS, $actual['event']);
130 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
131 $this->assertEmpty($actual['id']);
132 }
133
134 /**
135 * Make sure that new items are stored at the beginning
136 */
137 public function testHistoryOrder()
138 {
139 $history = new History(self::$historyFilePath);
140 $history->updateLink(['id' => 1]);
141 $actual = $history->getHistory()[0];
142 $this->assertEquals(History::UPDATED, $actual['event']);
143 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
144 $this->assertEquals(1, $actual['id']);
145
146 $history->addLink(['id' => 1]);
147 $actual = $history->getHistory()[0];
148 $this->assertEquals(History::CREATED, $actual['event']);
149 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
150 $this->assertEquals(1, $actual['id']);
151 }
152
153 /**
154 * Re-read history from file after writing an event
155 */
156 public function testHistoryRead()
157 {
158 $history = new History(self::$historyFilePath);
159 $history->updateLink(['id' => 1]);
160 $history = new History(self::$historyFilePath);
161 $actual = $history->getHistory()[0];
162 $this->assertEquals(History::UPDATED, $actual['event']);
163 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
164 $this->assertEquals(1, $actual['id']);
165 }
166
167 /**
168 * Re-read history from file after writing an event and make sure that the order is correct
169 */
170 public function testHistoryOrderRead()
171 {
172 $history = new History(self::$historyFilePath);
173 $history->updateLink(['id' => 1]);
174 $history->addLink(['id' => 1]);
175
176 $history = new History(self::$historyFilePath);
177 $actual = $history->getHistory()[0];
178 $this->assertEquals(History::CREATED, $actual['event']);
179 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
180 $this->assertEquals(1, $actual['id']);
181
182 $actual = $history->getHistory()[1];
183 $this->assertEquals(History::UPDATED, $actual['event']);
184 $this->assertTrue(new DateTime('-2 seconds') < $actual['datetime']);
185 $this->assertEquals(1, $actual['id']);
186 }
187
188 /**
189 * Test retention time: delete old entries.
190 */
191 public function testHistoryRententionTime()
192 {
193 $history = new History(self::$historyFilePath, 5);
194 $history->updateLink(['id' => 1]);
195 $this->assertEquals(1, count($history->getHistory()));
196 $arr = $history->getHistory();
197 $arr[0]['datetime'] = new DateTime('-1 hour');
198 FileUtils::writeFlatDB(self::$historyFilePath, $arr);
199
200 $history = new History(self::$historyFilePath, 60);
201 $this->assertEquals(1, count($history->getHistory()));
202 $this->assertEquals(1, $history->getHistory()[0]['id']);
203 $history->updateLink(['id' => 2]);
204 $this->assertEquals(1, count($history->getHistory()));
205 $this->assertEquals(2, $history->getHistory()[0]['id']);
206 }
207}
diff --git a/tests/HttpUtils/IsHttpsTest.php b/tests/HttpUtils/IsHttpsTest.php
new file mode 100644
index 00000000..097f2bcf
--- /dev/null
+++ b/tests/HttpUtils/IsHttpsTest.php
@@ -0,0 +1,36 @@
1<?php
2
3
4/**
5 * Class IsHttpsTest
6 *
7 * Test class for is_https() function.
8 */
9class IsHttpsTest extends PHPUnit_Framework_TestCase
10{
11
12 /**
13 * Test is_https with HTTPS values.
14 */
15 public function testIsHttpsTrue()
16 {
17 $this->assertTrue(is_https(['HTTPS' => true]));
18 $this->assertTrue(is_https(['HTTPS' => '1']));
19 $this->assertTrue(is_https(['HTTPS' => false, 'HTTP_X_FORWARDED_PORT' => 443]));
20 $this->assertTrue(is_https(['HTTPS' => false, 'HTTP_X_FORWARDED_PORT' => '443']));
21 $this->assertTrue(is_https(['HTTPS' => false, 'HTTP_X_FORWARDED_PORT' => '443,123,456,']));
22 }
23
24 /**
25 * Test is_https with HTTP values.
26 */
27 public function testIsHttpsFalse()
28 {
29 $this->assertFalse(is_https([]));
30 $this->assertFalse(is_https(['HTTPS' => false]));
31 $this->assertFalse(is_https(['HTTPS' => '0']));
32 $this->assertFalse(is_https(['HTTPS' => false, 'HTTP_X_FORWARDED_PORT' => 123]));
33 $this->assertFalse(is_https(['HTTPS' => false, 'HTTP_X_FORWARDED_PORT' => '123']));
34 $this->assertFalse(is_https(['HTTPS' => false, 'HTTP_X_FORWARDED_PORT' => ',123,456,']));
35 }
36}
diff --git a/tests/HttpUtils/ServerUrlTest.php b/tests/HttpUtils/ServerUrlTest.php
index 8a55a220..324b827a 100644
--- a/tests/HttpUtils/ServerUrlTest.php
+++ b/tests/HttpUtils/ServerUrlTest.php
@@ -39,6 +39,34 @@ class ServerUrlTest extends PHPUnit_Framework_TestCase
39 } 39 }
40 40
41 /** 41 /**
42 * Detect a Proxy that sets Forwarded-Host
43 */
44 public function testHttpsProxyForwardedHost()
45 {
46 $this->assertEquals(
47 'https://host.tld:8080',
48 server_url(
49 array(
50 'HTTP_X_FORWARDED_PROTO' => 'https',
51 'HTTP_X_FORWARDED_PORT' => '8080',
52 'HTTP_X_FORWARDED_HOST' => 'host.tld'
53 )
54 )
55 );
56
57 $this->assertEquals(
58 'https://host.tld:4974',
59 server_url(
60 array(
61 'HTTP_X_FORWARDED_PROTO' => 'https, https',
62 'HTTP_X_FORWARDED_PORT' => '4974, 80',
63 'HTTP_X_FORWARDED_HOST' => 'host.tld, example.com'
64 )
65 )
66 );
67 }
68
69 /**
42 * Detect a Proxy with SSL enabled 70 * Detect a Proxy with SSL enabled
43 */ 71 */
44 public function testHttpsProxyForward() 72 public function testHttpsProxyForward()
@@ -69,6 +97,19 @@ class ServerUrlTest extends PHPUnit_Framework_TestCase
69 ); 97 );
70 98
71 $this->assertEquals( 99 $this->assertEquals(
100 'https://host.tld',
101 server_url(
102 array(
103 'HTTPS' => 'Off',
104 'SERVER_NAME' => 'host.tld',
105 'SERVER_PORT' => '80',
106 'HTTP_X_FORWARDED_PROTO' => 'https',
107 'HTTP_X_FORWARDED_PORT' => '443'
108 )
109 )
110 );
111
112 $this->assertEquals(
72 'https://host.tld:4974', 113 'https://host.tld:4974',
73 server_url( 114 server_url(
74 array( 115 array(
@@ -145,4 +186,36 @@ class ServerUrlTest extends PHPUnit_Framework_TestCase
145 ) 186 )
146 ); 187 );
147 } 188 }
189
190 /**
191 * Misconfigured server (see #1022): Proxy HTTP but 443
192 */
193 public function testHttpWithPort433()
194 {
195 $this->assertEquals(
196 'https://host.tld',
197 server_url(
198 array(
199 'HTTPS' => 'Off',
200 'SERVER_NAME' => 'host.tld',
201 'SERVER_PORT' => '80',
202 'HTTP_X_FORWARDED_PROTO' => 'http',
203 'HTTP_X_FORWARDED_PORT' => '443'
204 )
205 )
206 );
207
208 $this->assertEquals(
209 'https://host.tld',
210 server_url(
211 array(
212 'HTTPS' => 'Off',
213 'SERVER_NAME' => 'host.tld',
214 'SERVER_PORT' => '80',
215 'HTTP_X_FORWARDED_PROTO' => 'https, http',
216 'HTTP_X_FORWARDED_PORT' => '443, 80'
217 )
218 )
219 );
220 }
148} 221}
diff --git a/tests/LanguagesTest.php b/tests/LanguagesTest.php
index 79c136c8..864ce630 100644
--- a/tests/LanguagesTest.php
+++ b/tests/LanguagesTest.php
@@ -1,41 +1,203 @@
1<?php 1<?php
2 2
3require_once 'application/Languages.php'; 3namespace Shaarli;
4
5use Shaarli\Config\ConfigManager;
4 6
5/** 7/**
6 * Class LanguagesTest. 8 * Class LanguagesTest.
7 */ 9 */
8class LanguagesTest extends PHPUnit_Framework_TestCase 10class LanguagesTest extends \PHPUnit_Framework_TestCase
9{ 11{
10 /** 12 /**
13 * @var string Config file path (without extension).
14 */
15 protected static $configFile = 'tests/utils/config/configJson';
16
17 /**
18 * @var ConfigManager
19 */
20 protected $conf;
21
22 /**
23 *
24 */
25 public function setUp()
26 {
27 $this->conf = new ConfigManager(self::$configFile);
28 }
29
30 /**
31 * Test t() with a simple non identified value.
32 */
33 public function testTranslateSingleNotIDGettext()
34 {
35 $this->conf->set('translation.mode', 'gettext');
36 new Languages('en', $this->conf);
37 $text = 'abcdé 564 fgK';
38 $this->assertEquals($text, t($text));
39 }
40
41 /**
42 * Test t() with a simple identified value in gettext mode.
43 */
44 public function testTranslateSingleIDGettext()
45 {
46 $this->conf->set('translation.mode', 'gettext');
47 new Languages('en', $this->conf);
48 $text = 'permalink';
49 $this->assertEquals($text, t($text));
50 }
51
52 /**
53 * Test t() with a non identified plural form in gettext mode.
54 */
55 public function testTranslatePluralNotIDGettext()
56 {
57 $this->conf->set('translation.mode', 'gettext');
58 new Languages('en', $this->conf);
59 $text = 'sandwich';
60 $nText = 'sandwiches';
61 $this->assertEquals('sandwiches', t($text, $nText, 0));
62 $this->assertEquals('sandwich', t($text, $nText, 1));
63 $this->assertEquals('sandwiches', t($text, $nText, 2));
64 }
65
66 /**
67 * Test t() with an identified plural form in gettext mode.
68 */
69 public function testTranslatePluralIDGettext()
70 {
71 $this->conf->set('translation.mode', 'gettext');
72 new Languages('en', $this->conf);
73 $text = 'shaare';
74 $nText = 'shaares';
75 // In english, zero is followed by plural form
76 $this->assertEquals('shaares', t($text, $nText, 0));
77 $this->assertEquals('shaare', t($text, $nText, 1));
78 $this->assertEquals('shaares', t($text, $nText, 2));
79 }
80
81 /**
11 * Test t() with a simple non identified value. 82 * Test t() with a simple non identified value.
12 */ 83 */
13 public function testTranslateSingleNotID() 84 public function testTranslateSingleNotIDPhp()
14 { 85 {
86 $this->conf->set('translation.mode', 'php');
87 new Languages('en', $this->conf);
15 $text = 'abcdé 564 fgK'; 88 $text = 'abcdé 564 fgK';
16 $this->assertEquals($text, t($text)); 89 $this->assertEquals($text, t($text));
17 } 90 }
18 91
19 /** 92 /**
20 * Test t() with a non identified plural form. 93 * Test t() with a simple identified value in PHP mode.
21 */ 94 */
22 public function testTranslatePluralNotID() 95 public function testTranslateSingleIDPhp()
23 { 96 {
24 $text = '%s sandwich'; 97 $this->conf->set('translation.mode', 'php');
25 $nText = '%s sandwiches'; 98 new Languages('en', $this->conf);
26 $this->assertEquals('0 sandwich', t($text, $nText)); 99 $text = 'permalink';
27 $this->assertEquals('1 sandwich', t($text, $nText, 1)); 100 $this->assertEquals($text, t($text));
28 $this->assertEquals('2 sandwiches', t($text, $nText, 2));
29 } 101 }
30 102
31 /** 103 /**
32 * Test t() with a non identified invalid plural form. 104 * Test t() with a non identified plural form in PHP mode.
33 */ 105 */
34 public function testTranslatePluralNotIDInvalid() 106 public function testTranslatePluralNotIDPhp()
35 { 107 {
108 $this->conf->set('translation.mode', 'php');
109 new Languages('en', $this->conf);
36 $text = 'sandwich'; 110 $text = 'sandwich';
37 $nText = 'sandwiches'; 111 $nText = 'sandwiches';
112 $this->assertEquals('sandwiches', t($text, $nText, 0));
38 $this->assertEquals('sandwich', t($text, $nText, 1)); 113 $this->assertEquals('sandwich', t($text, $nText, 1));
39 $this->assertEquals('sandwiches', t($text, $nText, 2)); 114 $this->assertEquals('sandwiches', t($text, $nText, 2));
40 } 115 }
116
117 /**
118 * Test t() with an identified plural form in PHP mode.
119 */
120 public function testTranslatePluralIDPhp()
121 {
122 $this->conf->set('translation.mode', 'php');
123 new Languages('en', $this->conf);
124 $text = 'shaare';
125 $nText = 'shaares';
126 // In english, zero is followed by plural form
127 $this->assertEquals('shaares', t($text, $nText, 0));
128 $this->assertEquals('shaare', t($text, $nText, 1));
129 $this->assertEquals('shaares', t($text, $nText, 2));
130 }
131
132 /**
133 * Test t() with an invalid language set in the configuration in gettext mode.
134 */
135 public function testTranslateWithInvalidConfLanguageGettext()
136 {
137 $this->conf->set('translation.mode', 'gettext');
138 $this->conf->set('translation.language', 'nope');
139 new Languages('fr', $this->conf);
140 $text = 'grumble';
141 $this->assertEquals($text, t($text));
142 }
143
144 /**
145 * Test t() with an invalid language set in the configuration in PHP mode.
146 */
147 public function testTranslateWithInvalidConfLanguagePhp()
148 {
149 $this->conf->set('translation.mode', 'php');
150 $this->conf->set('translation.language', 'nope');
151 new Languages('fr', $this->conf);
152 $text = 'grumble';
153 $this->assertEquals($text, t($text));
154 }
155
156 /**
157 * Test t() with an invalid language set with auto language in gettext mode.
158 */
159 public function testTranslateWithInvalidAutoLanguageGettext()
160 {
161 $this->conf->set('translation.mode', 'gettext');
162 new Languages('nope', $this->conf);
163 $text = 'grumble';
164 $this->assertEquals($text, t($text));
165 }
166
167 /**
168 * Test t() with an invalid language set with auto language in PHP mode.
169 */
170 public function testTranslateWithInvalidAutoLanguagePhp()
171 {
172 $this->conf->set('translation.mode', 'php');
173 new Languages('nope', $this->conf);
174 $text = 'grumble';
175 $this->assertEquals($text, t($text));
176 }
177
178 /**
179 * Test t() with an extension language file in gettext mode
180 */
181 public function testTranslationExtensionGettext()
182 {
183 $this->conf->set('translation.mode', 'gettext');
184 $this->conf->set('translation.extensions.test', 'tests/utils/languages/');
185 new Languages('en', $this->conf);
186 $txt = 'car'; // ignore me poedit
187 $this->assertEquals('car', t($txt, $txt, 1, 'test'));
188 $this->assertEquals('Search', t('Search', 'Search', 1, 'test'));
189 }
190
191 /**
192 * Test t() with an extension language file in PHP mode
193 */
194 public function testTranslationExtensionPhp()
195 {
196 $this->conf->set('translation.mode', 'php');
197 $this->conf->set('translation.extensions.test', 'tests/utils/languages/');
198 new Languages('en', $this->conf);
199 $txt = 'car'; // ignore me poedit
200 $this->assertEquals('car', t($txt, $txt, 1, 'test'));
201 $this->assertEquals('Search', t('Search', 'Search', 1, 'test'));
202 }
41} 203}
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php
index 1f62a34a..5b2f3667 100644
--- a/tests/LinkDBTest.php
+++ b/tests/LinkDBTest.php
@@ -101,7 +101,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
101 * Attempt to instantiate a LinkDB whereas the datastore is not writable 101 * Attempt to instantiate a LinkDB whereas the datastore is not writable
102 * 102 *
103 * @expectedException IOException 103 * @expectedException IOException
104 * @expectedExceptionMessageRegExp /Error accessing\nnull/ 104 * @expectedExceptionMessageRegExp /Error accessing "null"/
105 */ 105 */
106 public function testConstructDatastoreNotWriteable() 106 public function testConstructDatastoreNotWriteable()
107 { 107 {
@@ -297,7 +297,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
297 'sTuff' => 2, 297 'sTuff' => 2,
298 'ut' => 1, 298 'ut' => 1,
299 ), 299 ),
300 self::$publicLinkDB->allTags() 300 self::$publicLinkDB->linksCountPerTag()
301 ); 301 );
302 302
303 $this->assertEquals( 303 $this->assertEquals(
@@ -325,7 +325,34 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
325 'tag4' => 1, 325 'tag4' => 1,
326 'ut' => 1, 326 'ut' => 1,
327 ), 327 ),
328 self::$privateLinkDB->allTags() 328 self::$privateLinkDB->linksCountPerTag()
329 );
330 $this->assertEquals(
331 array(
332 'web' => 4,
333 'cartoon' => 2,
334 'gnu' => 1,
335 'dev' => 1,
336 'samba' => 1,
337 'media' => 1,
338 'html' => 1,
339 'w3c' => 1,
340 'css' => 1,
341 'Mercurial' => 1,
342 '.hidden' => 1,
343 'hashtag' => 1,
344 ),
345 self::$privateLinkDB->linksCountPerTag(['web'])
346 );
347 $this->assertEquals(
348 array(
349 'web' => 1,
350 'html' => 1,
351 'w3c' => 1,
352 'css' => 1,
353 'Mercurial' => 1,
354 ),
355 self::$privateLinkDB->linksCountPerTag(['web'], 'private')
329 ); 356 );
330 } 357 }
331 358
@@ -448,7 +475,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
448 public function testReorderLinksDesc() 475 public function testReorderLinksDesc()
449 { 476 {
450 self::$privateLinkDB->reorder('ASC'); 477 self::$privateLinkDB->reorder('ASC');
451 $linkIds = array(42, 4, 1, 0, 7, 6, 8, 41); 478 $linkIds = array(42, 4, 9, 1, 0, 7, 6, 8, 41);
452 $cpt = 0; 479 $cpt = 0;
453 foreach (self::$privateLinkDB as $key => $value) { 480 foreach (self::$privateLinkDB as $key => $value) {
454 $this->assertEquals($linkIds[$cpt++], $key); 481 $this->assertEquals($linkIds[$cpt++], $key);
@@ -460,4 +487,59 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
460 $this->assertEquals($linkIds[$cpt++], $key); 487 $this->assertEquals($linkIds[$cpt++], $key);
461 } 488 }
462 } 489 }
490
491 /**
492 * Test rename tag with a valid value present in multiple links
493 */
494 public function testRenameTagMultiple()
495 {
496 self::$refDB->write(self::$testDatastore);
497 $linkDB = new LinkDB(self::$testDatastore, true, false);
498
499 $res = $linkDB->renameTag('cartoon', 'Taz');
500 $this->assertEquals(3, count($res));
501 $this->assertContains(' Taz ', $linkDB[4]['tags']);
502 $this->assertContains(' Taz ', $linkDB[1]['tags']);
503 $this->assertContains(' Taz ', $linkDB[0]['tags']);
504 }
505
506 /**
507 * Test rename tag with a valid value
508 */
509 public function testRenameTagCaseSensitive()
510 {
511 self::$refDB->write(self::$testDatastore);
512 $linkDB = new LinkDB(self::$testDatastore, true, false, '');
513
514 $res = $linkDB->renameTag('sTuff', 'Taz');
515 $this->assertEquals(1, count($res));
516 $this->assertEquals('Taz', $linkDB[41]['tags']);
517 }
518
519 /**
520 * Test rename tag with invalid values
521 */
522 public function testRenameTagInvalid()
523 {
524 $linkDB = new LinkDB(self::$testDatastore, false, false);
525
526 $this->assertFalse($linkDB->renameTag('', 'test'));
527 $this->assertFalse($linkDB->renameTag('', ''));
528 // tag non existent
529 $this->assertEquals([], $linkDB->renameTag('test', ''));
530 $this->assertEquals([], $linkDB->renameTag('test', 'retest'));
531 }
532
533 /**
534 * Test delete tag with a valid value
535 */
536 public function testDeleteTag()
537 {
538 self::$refDB->write(self::$testDatastore);
539 $linkDB = new LinkDB(self::$testDatastore, true, false);
540
541 $res = $linkDB->renameTag('cartoon', null);
542 $this->assertEquals(3, count($res));
543 $this->assertNotContains('cartoon', $linkDB[4]['tags']);
544 }
463} 545}
diff --git a/tests/LinkFilterTest.php b/tests/LinkFilterTest.php
index 21d680a5..9cd6dbd4 100644
--- a/tests/LinkFilterTest.php
+++ b/tests/LinkFilterTest.php
@@ -8,17 +8,33 @@ require_once 'application/LinkFilter.php';
8class LinkFilterTest extends PHPUnit_Framework_TestCase 8class LinkFilterTest extends PHPUnit_Framework_TestCase
9{ 9{
10 /** 10 /**
11 * @var string Test datastore path.
12 */
13 protected static $testDatastore = 'sandbox/datastore.php';
14 /**
11 * @var LinkFilter instance. 15 * @var LinkFilter instance.
12 */ 16 */
13 protected static $linkFilter; 17 protected static $linkFilter;
14 18
15 /** 19 /**
20 * @var ReferenceLinkDB instance
21 */
22 protected static $refDB;
23
24 /**
25 * @var LinkDB instance
26 */
27 protected static $linkDB;
28
29 /**
16 * Instanciate linkFilter with ReferenceLinkDB data. 30 * Instanciate linkFilter with ReferenceLinkDB data.
17 */ 31 */
18 public static function setUpBeforeClass() 32 public static function setUpBeforeClass()
19 { 33 {
20 $refDB = new ReferenceLinkDB(); 34 self::$refDB = new ReferenceLinkDB();
21 self::$linkFilter = new LinkFilter($refDB->getLinks()); 35 self::$refDB->write(self::$testDatastore);
36 self::$linkDB = new LinkDB(self::$testDatastore, true, false);
37 self::$linkFilter = new LinkFilter(self::$linkDB);
22 } 38 }
23 39
24 /** 40 /**
@@ -27,14 +43,30 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
27 public function testFilter() 43 public function testFilter()
28 { 44 {
29 $this->assertEquals( 45 $this->assertEquals(
30 ReferenceLinkDB::$NB_LINKS_TOTAL, 46 self::$refDB->countLinks(),
31 count(self::$linkFilter->filter('', '')) 47 count(self::$linkFilter->filter('', ''))
32 ); 48 );
33 49
50 $this->assertEquals(
51 self::$refDB->countLinks(),
52 count(self::$linkFilter->filter('', '', 'all'))
53 );
54
55 $this->assertEquals(
56 self::$refDB->countLinks(),
57 count(self::$linkFilter->filter('', '', 'randomstr'))
58 );
59
34 // Private only. 60 // Private only.
35 $this->assertEquals( 61 $this->assertEquals(
36 2, 62 self::$refDB->countPrivateLinks(),
37 count(self::$linkFilter->filter('', '', false, true)) 63 count(self::$linkFilter->filter('', '', false, 'private'))
64 );
65
66 // Public only.
67 $this->assertEquals(
68 self::$refDB->countPublicLinks(),
69 count(self::$linkFilter->filter('', '', false, 'public'))
38 ); 70 );
39 71
40 $this->assertEquals( 72 $this->assertEquals(
@@ -43,6 +75,11 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
43 ); 75 );
44 76
45 $this->assertEquals( 77 $this->assertEquals(
78 self::$refDB->countUntaggedLinks(),
79 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, /*$request=*/'', /*$casesensitive=*/false, /*$visibility=*/'all', /*$untaggedonly=*/true))
80 );
81
82 $this->assertEquals(
46 ReferenceLinkDB::$NB_LINKS_TOTAL, 83 ReferenceLinkDB::$NB_LINKS_TOTAL,
47 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '')) 84 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, ''))
48 ); 85 );
@@ -58,10 +95,26 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
58 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false)) 95 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false))
59 ); 96 );
60 97
98 $this->assertEquals(
99 4,
100 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'all'))
101 );
102
103 $this->assertEquals(
104 4,
105 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'default-blabla'))
106 );
107
61 // Private only. 108 // Private only.
62 $this->assertEquals( 109 $this->assertEquals(
63 1, 110 1,
64 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, true)) 111 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'private'))
112 );
113
114 // Public only.
115 $this->assertEquals(
116 3,
117 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, 'web', false, 'public'))
65 ); 118 );
66 } 119 }
67 120
@@ -109,7 +162,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
109 public function testFilterDay() 162 public function testFilterDay()
110 { 163 {
111 $this->assertEquals( 164 $this->assertEquals(
112 3, 165 4,
113 count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206')) 166 count(self::$linkFilter->filter(LinkFilter::$FILTER_DAY, '20121206'))
114 ); 167 );
115 } 168 }
@@ -253,14 +306,30 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
253 public function testFilterFullTextTags() 306 public function testFilterFullTextTags()
254 { 307 {
255 $this->assertEquals( 308 $this->assertEquals(
256 2, 309 6,
257 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'gnu')) 310 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web'))
311 );
312
313 $this->assertEquals(
314 6,
315 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', 'all'))
316 );
317
318 $this->assertEquals(
319 6,
320 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', 'bla'))
258 ); 321 );
259 322
260 // Private only. 323 // Private only.
261 $this->assertEquals( 324 $this->assertEquals(
262 1, 325 1,
263 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', false, true)) 326 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', false, 'private'))
327 );
328
329 // Public only.
330 $this->assertEquals(
331 5,
332 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, 'web', false, 'public'))
264 ); 333 );
265 } 334 }
266 335
@@ -286,7 +355,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
286 ); 355 );
287 356
288 $this->assertEquals( 357 $this->assertEquals(
289 7, 358 ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
290 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution')) 359 count(self::$linkFilter->filter(LinkFilter::$FILTER_TEXT, '-revolution'))
291 ); 360 );
292 } 361 }
@@ -346,7 +415,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
346 ); 415 );
347 416
348 $this->assertEquals( 417 $this->assertEquals(
349 7, 418 ReferenceLinkDB::$NB_LINKS_TOTAL - 1,
350 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free')) 419 count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '-free'))
351 ); 420 );
352 } 421 }
@@ -376,6 +445,13 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
376 1, 445 1,
377 count(self::$linkFilter->filter( 446 count(self::$linkFilter->filter(
378 LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, 447 LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
448 array(false, 'PSR-2')
449 ))
450 );
451 $this->assertEquals(
452 1,
453 count(self::$linkFilter->filter(
454 LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT,
379 array($tags, '') 455 array($tags, '')
380 )) 456 ))
381 ); 457 );
@@ -409,7 +485,7 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase
409 LinkFilter::$FILTER_TAG, 485 LinkFilter::$FILTER_TAG,
410 $hashtag, 486 $hashtag,
411 false, 487 false,
412 true 488 'private'
413 )) 489 ))
414 ); 490 );
415 } 491 }
diff --git a/tests/LinkUtilsTest.php b/tests/LinkUtilsTest.php
index 7c0d4b0b..7fbd59b0 100644
--- a/tests/LinkUtilsTest.php
+++ b/tests/LinkUtilsTest.php
@@ -29,27 +29,13 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
29 } 29 }
30 30
31 /** 31 /**
32 * Test get_charset() with all priorities.
33 */
34 public function testGetCharset()
35 {
36 $headers = array('Content-Type' => 'text/html; charset=Headers');
37 $html = '<html><meta>stuff</meta><meta charset="Html"/></html>';
38 $default = 'default';
39 $this->assertEquals('headers', get_charset($headers, $html, $default));
40 $this->assertEquals('html', get_charset(array(), $html, $default));
41 $this->assertEquals($default, get_charset(array(), '', $default));
42 $this->assertEquals('utf-8', get_charset(array(), ''));
43 }
44
45 /**
46 * Test headers_extract_charset() when the charset is found. 32 * Test headers_extract_charset() when the charset is found.
47 */ 33 */
48 public function testHeadersExtractExistentCharset() 34 public function testHeadersExtractExistentCharset()
49 { 35 {
50 $charset = 'x-MacCroatian'; 36 $charset = 'x-MacCroatian';
51 $headers = array('Content-Type' => 'text/html; charset='. $charset); 37 $headers = 'text/html; charset='. $charset;
52 $this->assertEquals(strtolower($charset), headers_extract_charset($headers)); 38 $this->assertEquals(strtolower($charset), header_extract_charset($headers));
53 } 39 }
54 40
55 /** 41 /**
@@ -57,11 +43,11 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
57 */ 43 */
58 public function testHeadersExtractNonExistentCharset() 44 public function testHeadersExtractNonExistentCharset()
59 { 45 {
60 $headers = array(); 46 $headers = '';
61 $this->assertFalse(headers_extract_charset($headers)); 47 $this->assertFalse(header_extract_charset($headers));
62 48
63 $headers = array('Content-Type' => 'text/html'); 49 $headers = 'text/html';
64 $this->assertFalse(headers_extract_charset($headers)); 50 $this->assertFalse(header_extract_charset($headers));
65 } 51 }
66 52
67 /** 53 /**
@@ -86,6 +72,131 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
86 } 72 }
87 73
88 /** 74 /**
75 * Test the download callback with valid value
76 */
77 public function testCurlDownloadCallbackOk()
78 {
79 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
80 $data = [
81 'HTTP/1.1 200 OK',
82 'Server: GitHub.com',
83 'Date: Sat, 28 Oct 2017 12:01:33 GMT',
84 'Content-Type: text/html; charset=utf-8',
85 'Status: 200 OK',
86 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
87 '<title>ignored</title>',
88 ];
89 foreach ($data as $key => $line) {
90 $ignore = null;
91 $expected = $key !== 'end' ? strlen($line) : false;
92 $this->assertEquals($expected, $callback($ignore, $line));
93 if ($expected === false) {
94 break;
95 }
96 }
97 $this->assertEquals('utf-8', $charset);
98 $this->assertEquals('Refactoring · GitHub', $title);
99 }
100
101 /**
102 * Test the download callback with valid values and no charset
103 */
104 public function testCurlDownloadCallbackOkNoCharset()
105 {
106 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
107 $data = [
108 'HTTP/1.1 200 OK',
109 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
110 '<title>ignored</title>',
111 ];
112 foreach ($data as $key => $line) {
113 $ignore = null;
114 $this->assertEquals(strlen($line), $callback($ignore, $line));
115 }
116 $this->assertEmpty($charset);
117 $this->assertEquals('Refactoring · GitHub', $title);
118 }
119
120 /**
121 * Test the download callback with valid values and no charset
122 */
123 public function testCurlDownloadCallbackOkHtmlCharset()
124 {
125 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_no_charset');
126 $data = [
127 'HTTP/1.1 200 OK',
128 '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
129 'end' => 'th=device-width"><title>Refactoring · GitHub</title><link rel="search" type="application/opensea',
130 '<title>ignored</title>',
131 ];
132 foreach ($data as $key => $line) {
133 $ignore = null;
134 $expected = $key !== 'end' ? strlen($line) : false;
135 $this->assertEquals($expected, $callback($ignore, $line));
136 if ($expected === false) {
137 break;
138 }
139 }
140 $this->assertEquals('utf-8', $charset);
141 $this->assertEquals('Refactoring · GitHub', $title);
142 }
143
144 /**
145 * Test the download callback with valid values and no title
146 */
147 public function testCurlDownloadCallbackOkNoTitle()
148 {
149 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ok');
150 $data = [
151 'HTTP/1.1 200 OK',
152 'end' => 'th=device-width">Refactoring · GitHub<link rel="search" type="application/opensea',
153 'ignored',
154 ];
155 foreach ($data as $key => $line) {
156 $ignore = null;
157 $this->assertEquals(strlen($line), $callback($ignore, $line));
158 }
159 $this->assertEquals('utf-8', $charset);
160 $this->assertEmpty($title);
161 }
162
163 /**
164 * Test the download callback with an invalid content type.
165 */
166 public function testCurlDownloadCallbackInvalidContentType()
167 {
168 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_ct_ko');
169 $ignore = null;
170 $this->assertFalse($callback($ignore, ''));
171 $this->assertEmpty($charset);
172 $this->assertEmpty($title);
173 }
174
175 /**
176 * Test the download callback with an invalid response code.
177 */
178 public function testCurlDownloadCallbackInvalidResponseCode()
179 {
180 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rc_ko');
181 $ignore = null;
182 $this->assertFalse($callback($ignore, ''));
183 $this->assertEmpty($charset);
184 $this->assertEmpty($title);
185 }
186
187 /**
188 * Test the download callback with an invalid content type and response code.
189 */
190 public function testCurlDownloadCallbackInvalidContentTypeAndResponseCode()
191 {
192 $callback = get_curl_download_callback($charset, $title, 'ut_curl_getinfo_rs_ct_ko');
193 $ignore = null;
194 $this->assertFalse($callback($ignore, ''));
195 $this->assertEmpty($charset);
196 $this->assertEmpty($title);
197 }
198
199 /**
89 * Test count_private. 200 * Test count_private.
90 */ 201 */
91 public function testCountPrivateLinks() 202 public function testCountPrivateLinks()
@@ -103,6 +214,16 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
103 $expectedText = 'stuff <a href="http://hello.there/is=someone#here">http://hello.there/is=someone#here</a> otherstuff'; 214 $expectedText = 'stuff <a href="http://hello.there/is=someone#here">http://hello.there/is=someone#here</a> otherstuff';
104 $processedText = text2clickable($text, ''); 215 $processedText = text2clickable($text, '');
105 $this->assertEquals($expectedText, $processedText); 216 $this->assertEquals($expectedText, $processedText);
217
218 $text = 'stuff http://hello.there/is=someone#here(please) otherstuff';
219 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">http://hello.there/is=someone#here(please)</a> otherstuff';
220 $processedText = text2clickable($text, '');
221 $this->assertEquals($expectedText, $processedText);
222
223 $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
224 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">http://hello.there/is=someone#here(please)&no</a> otherstuff';
225 $processedText = text2clickable($text, '');
226 $this->assertEquals($expectedText, $processedText);
106 } 227 }
107 228
108 /** 229 /**
@@ -121,6 +242,21 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
121 } 242 }
122 243
123 /** 244 /**
245 * Test text2clickable a redirector set and without URL encode.
246 */
247 public function testText2clickableWithRedirectorDontEncode()
248 {
249 $text = 'stuff http://hello.there/?is=someone&or=something#here otherstuff';
250 $redirector = 'http://redirector.to';
251 $expectedText = 'stuff <a href="'.
252 $redirector .
253 'http://hello.there/?is=someone&or=something#here' .
254 '">http://hello.there/?is=someone&or=something#here</a> otherstuff';
255 $processedText = text2clickable($text, $redirector, false);
256 $this->assertEquals($expectedText, $processedText);
257 }
258
259 /**
124 * Test testSpace2nbsp. 260 * Test testSpace2nbsp.
125 */ 261 */
126 public function testSpace2nbsp() 262 public function testSpace2nbsp()
@@ -182,3 +318,96 @@ class LinkUtilsTest extends PHPUnit_Framework_TestCase
182 return str_replace('$1', $hashtag, $hashtagLink); 318 return str_replace('$1', $hashtag, $hashtagLink);
183 } 319 }
184} 320}
321
322// old style mock: PHPUnit doesn't allow function mock
323
324/**
325 * Returns code 200 or html content type.
326 *
327 * @param resource $ch cURL resource
328 * @param int $type cURL info type
329 *
330 * @return int|string 200 or 'text/html'
331 */
332function ut_curl_getinfo_ok($ch, $type)
333{
334 switch ($type) {
335 case CURLINFO_RESPONSE_CODE:
336 return 200;
337 case CURLINFO_CONTENT_TYPE:
338 return 'text/html; charset=utf-8';
339 }
340}
341
342/**
343 * Returns code 200 or html content type without charset.
344 *
345 * @param resource $ch cURL resource
346 * @param int $type cURL info type
347 *
348 * @return int|string 200 or 'text/html'
349 */
350function ut_curl_getinfo_no_charset($ch, $type)
351{
352 switch ($type) {
353 case CURLINFO_RESPONSE_CODE:
354 return 200;
355 case CURLINFO_CONTENT_TYPE:
356 return 'text/html';
357 }
358}
359
360/**
361 * Invalid response code.
362 *
363 * @param resource $ch cURL resource
364 * @param int $type cURL info type
365 *
366 * @return int|string 404 or 'text/html'
367 */
368function ut_curl_getinfo_rc_ko($ch, $type)
369{
370 switch ($type) {
371 case CURLINFO_RESPONSE_CODE:
372 return 404;
373 case CURLINFO_CONTENT_TYPE:
374 return 'text/html; charset=utf-8';
375 }
376}
377
378/**
379 * Invalid content type.
380 *
381 * @param resource $ch cURL resource
382 * @param int $type cURL info type
383 *
384 * @return int|string 200 or 'text/plain'
385 */
386function ut_curl_getinfo_ct_ko($ch, $type)
387{
388 switch ($type) {
389 case CURLINFO_RESPONSE_CODE:
390 return 200;
391 case CURLINFO_CONTENT_TYPE:
392 return 'text/plain';
393 }
394}
395
396/**
397 * Invalid response code and content type.
398 *
399 * @param resource $ch cURL resource
400 * @param int $type cURL info type
401 *
402 * @return int|string 404 or 'text/plain'
403 */
404function ut_curl_getinfo_rs_ct_ko($ch, $type)
405{
406 switch ($type) {
407 case CURLINFO_RESPONSE_CODE:
408 return 404;
409 case CURLINFO_CONTENT_TYPE:
410 return 'text/plain';
411 }
412}
413
diff --git a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php
index 0ca07eac..4961aa2c 100644
--- a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php
+++ b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php
@@ -2,6 +2,7 @@
2 2
3require_once 'application/NetscapeBookmarkUtils.php'; 3require_once 'application/NetscapeBookmarkUtils.php';
4 4
5use Shaarli\Config\ConfigManager;
5 6
6/** 7/**
7 * Utility function to load a file's metadata in a $_FILES-like array 8 * Utility function to load a file's metadata in a $_FILES-like array
@@ -33,6 +34,11 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
33 protected static $testDatastore = 'sandbox/datastore.php'; 34 protected static $testDatastore = 'sandbox/datastore.php';
34 35
35 /** 36 /**
37 * @var string History file path
38 */
39 protected static $historyFilePath = 'sandbox/history.php';
40
41 /**
36 * @var LinkDB private LinkDB instance 42 * @var LinkDB private LinkDB instance
37 */ 43 */
38 protected $linkDb = null; 44 protected $linkDb = null;
@@ -43,6 +49,16 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
43 protected $pagecache = 'tests'; 49 protected $pagecache = 'tests';
44 50
45 /** 51 /**
52 * @var ConfigManager instance.
53 */
54 protected $conf;
55
56 /**
57 * @var History instance.
58 */
59 protected $history;
60
61 /**
46 * @var string Save the current timezone. 62 * @var string Save the current timezone.
47 */ 63 */
48 protected static $defaultTimeZone; 64 protected static $defaultTimeZone;
@@ -65,6 +81,17 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
65 // start with an empty datastore 81 // start with an empty datastore
66 file_put_contents(self::$testDatastore, '<?php /* S7QysKquBQA= */ ?>'); 82 file_put_contents(self::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
67 $this->linkDb = new LinkDB(self::$testDatastore, true, false); 83 $this->linkDb = new LinkDB(self::$testDatastore, true, false);
84 $this->conf = new ConfigManager('tests/utils/config/configJson');
85 $this->conf->set('resource.page_cache', $this->pagecache);
86 $this->history = new History(self::$historyFilePath);
87 }
88
89 /**
90 * Delete history file.
91 */
92 public function tearDown()
93 {
94 @unlink(self::$historyFilePath);
68 } 95 }
69 96
70 public static function tearDownAfterClass() 97 public static function tearDownAfterClass()
@@ -81,7 +108,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
81 $this->assertEquals( 108 $this->assertEquals(
82 'File empty.htm (0 bytes) has an unknown file format.' 109 'File empty.htm (0 bytes) has an unknown file format.'
83 .' Nothing was imported.', 110 .' Nothing was imported.',
84 NetscapeBookmarkUtils::import(NULL, $files, NULL, NULL) 111 NetscapeBookmarkUtils::import(null, $files, null, $this->conf, $this->history)
85 ); 112 );
86 $this->assertEquals(0, count($this->linkDb)); 113 $this->assertEquals(0, count($this->linkDb));
87 } 114 }
@@ -94,7 +121,7 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
94 $files = file2array('no_doctype.htm'); 121 $files = file2array('no_doctype.htm');
95 $this->assertEquals( 122 $this->assertEquals(
96 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.', 123 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.',
97 NetscapeBookmarkUtils::import(NULL, $files, NULL, NULL) 124 NetscapeBookmarkUtils::import(null, $files, null, $this->conf, $this->history)
98 ); 125 );
99 $this->assertEquals(0, count($this->linkDb)); 126 $this->assertEquals(0, count($this->linkDb));
100 } 127 }
@@ -105,10 +132,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
105 public function testImportInternetExplorerEncoding() 132 public function testImportInternetExplorerEncoding()
106 { 133 {
107 $files = file2array('internet_explorer_encoding.htm'); 134 $files = file2array('internet_explorer_encoding.htm');
108 $this->assertEquals( 135 $this->assertStringMatchesFormat(
109 'File internet_explorer_encoding.htm (356 bytes) was successfully processed:' 136 'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:'
110 .' 1 links imported, 0 links overwritten, 0 links skipped.', 137 .' 1 links imported, 0 links overwritten, 0 links skipped.',
111 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache) 138 NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history)
112 ); 139 );
113 $this->assertEquals(1, count($this->linkDb)); 140 $this->assertEquals(1, count($this->linkDb));
114 $this->assertEquals(0, count_private($this->linkDb)); 141 $this->assertEquals(0, count_private($this->linkDb));
@@ -134,10 +161,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
134 public function testImportNested() 161 public function testImportNested()
135 { 162 {
136 $files = file2array('netscape_nested.htm'); 163 $files = file2array('netscape_nested.htm');
137 $this->assertEquals( 164 $this->assertStringMatchesFormat(
138 'File netscape_nested.htm (1337 bytes) was successfully processed:' 165 'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:'
139 .' 8 links imported, 0 links overwritten, 0 links skipped.', 166 .' 8 links imported, 0 links overwritten, 0 links skipped.',
140 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache) 167 NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history)
141 ); 168 );
142 $this->assertEquals(8, count($this->linkDb)); 169 $this->assertEquals(8, count($this->linkDb));
143 $this->assertEquals(2, count_private($this->linkDb)); 170 $this->assertEquals(2, count_private($this->linkDb));
@@ -256,10 +283,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
256 public function testImportDefaultPrivacyNoPost() 283 public function testImportDefaultPrivacyNoPost()
257 { 284 {
258 $files = file2array('netscape_basic.htm'); 285 $files = file2array('netscape_basic.htm');
259 $this->assertEquals( 286 $this->assertStringMatchesFormat(
260 'File netscape_basic.htm (482 bytes) was successfully processed:' 287 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
261 .' 2 links imported, 0 links overwritten, 0 links skipped.', 288 .' 2 links imported, 0 links overwritten, 0 links skipped.',
262 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache) 289 NetscapeBookmarkUtils::import([], $files, $this->linkDb, $this->conf, $this->history)
263 ); 290 );
264 291
265 $this->assertEquals(2, count($this->linkDb)); 292 $this->assertEquals(2, count($this->linkDb));
@@ -301,10 +328,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
301 { 328 {
302 $post = array('privacy' => 'default'); 329 $post = array('privacy' => 'default');
303 $files = file2array('netscape_basic.htm'); 330 $files = file2array('netscape_basic.htm');
304 $this->assertEquals( 331 $this->assertStringMatchesFormat(
305 'File netscape_basic.htm (482 bytes) was successfully processed:' 332 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
306 .' 2 links imported, 0 links overwritten, 0 links skipped.', 333 .' 2 links imported, 0 links overwritten, 0 links skipped.',
307 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 334 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
308 ); 335 );
309 $this->assertEquals(2, count($this->linkDb)); 336 $this->assertEquals(2, count($this->linkDb));
310 $this->assertEquals(1, count_private($this->linkDb)); 337 $this->assertEquals(1, count_private($this->linkDb));
@@ -345,10 +372,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
345 { 372 {
346 $post = array('privacy' => 'public'); 373 $post = array('privacy' => 'public');
347 $files = file2array('netscape_basic.htm'); 374 $files = file2array('netscape_basic.htm');
348 $this->assertEquals( 375 $this->assertStringMatchesFormat(
349 'File netscape_basic.htm (482 bytes) was successfully processed:' 376 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
350 .' 2 links imported, 0 links overwritten, 0 links skipped.', 377 .' 2 links imported, 0 links overwritten, 0 links skipped.',
351 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 378 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
352 ); 379 );
353 $this->assertEquals(2, count($this->linkDb)); 380 $this->assertEquals(2, count($this->linkDb));
354 $this->assertEquals(0, count_private($this->linkDb)); 381 $this->assertEquals(0, count_private($this->linkDb));
@@ -369,10 +396,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
369 { 396 {
370 $post = array('privacy' => 'private'); 397 $post = array('privacy' => 'private');
371 $files = file2array('netscape_basic.htm'); 398 $files = file2array('netscape_basic.htm');
372 $this->assertEquals( 399 $this->assertStringMatchesFormat(
373 'File netscape_basic.htm (482 bytes) was successfully processed:' 400 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
374 .' 2 links imported, 0 links overwritten, 0 links skipped.', 401 .' 2 links imported, 0 links overwritten, 0 links skipped.',
375 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 402 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
376 ); 403 );
377 $this->assertEquals(2, count($this->linkDb)); 404 $this->assertEquals(2, count($this->linkDb));
378 $this->assertEquals(2, count_private($this->linkDb)); 405 $this->assertEquals(2, count_private($this->linkDb));
@@ -395,10 +422,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
395 422
396 // import links as private 423 // import links as private
397 $post = array('privacy' => 'private'); 424 $post = array('privacy' => 'private');
398 $this->assertEquals( 425 $this->assertStringMatchesFormat(
399 'File netscape_basic.htm (482 bytes) was successfully processed:' 426 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
400 .' 2 links imported, 0 links overwritten, 0 links skipped.', 427 .' 2 links imported, 0 links overwritten, 0 links skipped.',
401 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 428 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
402 ); 429 );
403 $this->assertEquals(2, count($this->linkDb)); 430 $this->assertEquals(2, count($this->linkDb));
404 $this->assertEquals(2, count_private($this->linkDb)); 431 $this->assertEquals(2, count_private($this->linkDb));
@@ -415,10 +442,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
415 'privacy' => 'public', 442 'privacy' => 'public',
416 'overwrite' => 'true' 443 'overwrite' => 'true'
417 ); 444 );
418 $this->assertEquals( 445 $this->assertStringMatchesFormat(
419 'File netscape_basic.htm (482 bytes) was successfully processed:' 446 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
420 .' 2 links imported, 2 links overwritten, 0 links skipped.', 447 .' 2 links imported, 2 links overwritten, 0 links skipped.',
421 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 448 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
422 ); 449 );
423 $this->assertEquals(2, count($this->linkDb)); 450 $this->assertEquals(2, count($this->linkDb));
424 $this->assertEquals(0, count_private($this->linkDb)); 451 $this->assertEquals(0, count_private($this->linkDb));
@@ -441,10 +468,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
441 468
442 // import links as public 469 // import links as public
443 $post = array('privacy' => 'public'); 470 $post = array('privacy' => 'public');
444 $this->assertEquals( 471 $this->assertStringMatchesFormat(
445 'File netscape_basic.htm (482 bytes) was successfully processed:' 472 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
446 .' 2 links imported, 0 links overwritten, 0 links skipped.', 473 .' 2 links imported, 0 links overwritten, 0 links skipped.',
447 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 474 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
448 ); 475 );
449 $this->assertEquals(2, count($this->linkDb)); 476 $this->assertEquals(2, count($this->linkDb));
450 $this->assertEquals(0, count_private($this->linkDb)); 477 $this->assertEquals(0, count_private($this->linkDb));
@@ -462,10 +489,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
462 'privacy' => 'private', 489 'privacy' => 'private',
463 'overwrite' => 'true' 490 'overwrite' => 'true'
464 ); 491 );
465 $this->assertEquals( 492 $this->assertStringMatchesFormat(
466 'File netscape_basic.htm (482 bytes) was successfully processed:' 493 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
467 .' 2 links imported, 2 links overwritten, 0 links skipped.', 494 .' 2 links imported, 2 links overwritten, 0 links skipped.',
468 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 495 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
469 ); 496 );
470 $this->assertEquals(2, count($this->linkDb)); 497 $this->assertEquals(2, count($this->linkDb));
471 $this->assertEquals(2, count_private($this->linkDb)); 498 $this->assertEquals(2, count_private($this->linkDb));
@@ -486,20 +513,20 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
486 { 513 {
487 $post = array('privacy' => 'public'); 514 $post = array('privacy' => 'public');
488 $files = file2array('netscape_basic.htm'); 515 $files = file2array('netscape_basic.htm');
489 $this->assertEquals( 516 $this->assertStringMatchesFormat(
490 'File netscape_basic.htm (482 bytes) was successfully processed:' 517 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
491 .' 2 links imported, 0 links overwritten, 0 links skipped.', 518 .' 2 links imported, 0 links overwritten, 0 links skipped.',
492 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 519 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
493 ); 520 );
494 $this->assertEquals(2, count($this->linkDb)); 521 $this->assertEquals(2, count($this->linkDb));
495 $this->assertEquals(0, count_private($this->linkDb)); 522 $this->assertEquals(0, count_private($this->linkDb));
496 523
497 // re-import as private, DO NOT enable overwriting 524 // re-import as private, DO NOT enable overwriting
498 $post = array('privacy' => 'private'); 525 $post = array('privacy' => 'private');
499 $this->assertEquals( 526 $this->assertStringMatchesFormat(
500 'File netscape_basic.htm (482 bytes) was successfully processed:' 527 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
501 .' 0 links imported, 0 links overwritten, 2 links skipped.', 528 .' 0 links imported, 0 links overwritten, 2 links skipped.',
502 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 529 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
503 ); 530 );
504 $this->assertEquals(2, count($this->linkDb)); 531 $this->assertEquals(2, count($this->linkDb));
505 $this->assertEquals(0, count_private($this->linkDb)); 532 $this->assertEquals(0, count_private($this->linkDb));
@@ -515,10 +542,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
515 'default_tags' => 'tag1,tag2 tag3' 542 'default_tags' => 'tag1,tag2 tag3'
516 ); 543 );
517 $files = file2array('netscape_basic.htm'); 544 $files = file2array('netscape_basic.htm');
518 $this->assertEquals( 545 $this->assertStringMatchesFormat(
519 'File netscape_basic.htm (482 bytes) was successfully processed:' 546 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
520 .' 2 links imported, 0 links overwritten, 0 links skipped.', 547 .' 2 links imported, 0 links overwritten, 0 links skipped.',
521 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 548 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
522 ); 549 );
523 $this->assertEquals(2, count($this->linkDb)); 550 $this->assertEquals(2, count($this->linkDb));
524 $this->assertEquals(0, count_private($this->linkDb)); 551 $this->assertEquals(0, count_private($this->linkDb));
@@ -542,10 +569,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
542 'default_tags' => 'tag1&,tag2 "tag3"' 569 'default_tags' => 'tag1&,tag2 "tag3"'
543 ); 570 );
544 $files = file2array('netscape_basic.htm'); 571 $files = file2array('netscape_basic.htm');
545 $this->assertEquals( 572 $this->assertStringMatchesFormat(
546 'File netscape_basic.htm (482 bytes) was successfully processed:' 573 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
547 .' 2 links imported, 0 links overwritten, 0 links skipped.', 574 .' 2 links imported, 0 links overwritten, 0 links skipped.',
548 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache) 575 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history)
549 ); 576 );
550 $this->assertEquals(2, count($this->linkDb)); 577 $this->assertEquals(2, count($this->linkDb));
551 $this->assertEquals(0, count_private($this->linkDb)); 578 $this->assertEquals(0, count_private($this->linkDb));
@@ -567,10 +594,10 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
567 public function testImportSameDate() 594 public function testImportSameDate()
568 { 595 {
569 $files = file2array('same_date.htm'); 596 $files = file2array('same_date.htm');
570 $this->assertEquals( 597 $this->assertStringMatchesFormat(
571 'File same_date.htm (453 bytes) was successfully processed:' 598 'File same_date.htm (453 bytes) was successfully processed in %d seconds:'
572 .' 3 links imported, 0 links overwritten, 0 links skipped.', 599 .' 3 links imported, 0 links overwritten, 0 links skipped.',
573 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache) 600 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->conf, $this->history)
574 ); 601 );
575 $this->assertEquals(3, count($this->linkDb)); 602 $this->assertEquals(3, count($this->linkDb));
576 $this->assertEquals(0, count_private($this->linkDb)); 603 $this->assertEquals(0, count_private($this->linkDb));
@@ -587,4 +614,27 @@ class BookmarkImportTest extends PHPUnit_Framework_TestCase
587 $this->linkDb[2]['id'] 614 $this->linkDb[2]['id']
588 ); 615 );
589 } 616 }
617
618 public function testImportCreateUpdateHistory()
619 {
620 $post = [
621 'privacy' => 'public',
622 'overwrite' => 'true',
623 ];
624 $files = file2array('netscape_basic.htm');
625 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history);
626 $history = $this->history->getHistory();
627 $this->assertEquals(1, count($history));
628 $this->assertEquals(History::IMPORT, $history[0]['event']);
629 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
630
631 // re-import as private, enable overwriting
632 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->conf, $this->history);
633 $history = $this->history->getHistory();
634 $this->assertEquals(2, count($history));
635 $this->assertEquals(History::IMPORT, $history[0]['event']);
636 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
637 $this->assertEquals(History::IMPORT, $history[1]['event']);
638 $this->assertTrue(new DateTime('-5 seconds') < $history[1]['datetime']);
639 }
590} 640}
diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php
index ddf48185..01de959c 100644
--- a/tests/PluginManagerTest.php
+++ b/tests/PluginManagerTest.php
@@ -1,4 +1,5 @@
1<?php 1<?php
2use Shaarli\Config\ConfigManager;
2 3
3/** 4/**
4 * Plugin Manager tests 5 * Plugin Manager tests
diff --git a/tests/SessionManagerTest.php b/tests/SessionManagerTest.php
new file mode 100644
index 00000000..aa75962a
--- /dev/null
+++ b/tests/SessionManagerTest.php
@@ -0,0 +1,149 @@
1<?php
2require_once 'tests/utils/FakeConfigManager.php';
3
4// Initialize reference data _before_ PHPUnit starts a session
5require_once 'tests/utils/ReferenceSessionIdHashes.php';
6ReferenceSessionIdHashes::genAllHashes();
7
8use \Shaarli\SessionManager;
9use \PHPUnit\Framework\TestCase;
10
11
12/**
13 * Test coverage for SessionManager
14 */
15class SessionManagerTest extends TestCase
16{
17 // Session ID hashes
18 protected static $sidHashes = null;
19
20 // Fake ConfigManager
21 protected static $conf = null;
22
23 /**
24 * Assign reference data
25 */
26 public static function setUpBeforeClass()
27 {
28 self::$sidHashes = ReferenceSessionIdHashes::getHashes();
29 self::$conf = new FakeConfigManager();
30 }
31
32 /**
33 * Generate a session token
34 */
35 public function testGenerateToken()
36 {
37 $session = [];
38 $sessionManager = new SessionManager($session, self::$conf);
39
40 $token = $sessionManager->generateToken();
41
42 $this->assertEquals(1, $session['tokens'][$token]);
43 $this->assertEquals(40, strlen($token));
44 }
45
46 /**
47 * Check a session token
48 */
49 public function testCheckToken()
50 {
51 $token = '4dccc3a45ad9d03e5542b90c37d8db6d10f2b38b';
52 $session = [
53 'tokens' => [
54 $token => 1,
55 ],
56 ];
57 $sessionManager = new SessionManager($session, self::$conf);
58
59 // check and destroy the token
60 $this->assertTrue($sessionManager->checkToken($token));
61 $this->assertFalse(isset($session['tokens'][$token]));
62
63 // ensure the token has been destroyed
64 $this->assertFalse($sessionManager->checkToken($token));
65 }
66
67 /**
68 * Generate and check a session token
69 */
70 public function testGenerateAndCheckToken()
71 {
72 $session = [];
73 $sessionManager = new SessionManager($session, self::$conf);
74
75 $token = $sessionManager->generateToken();
76
77 // ensure a token has been generated
78 $this->assertEquals(1, $session['tokens'][$token]);
79 $this->assertEquals(40, strlen($token));
80
81 // check and destroy the token
82 $this->assertTrue($sessionManager->checkToken($token));
83 $this->assertFalse(isset($session['tokens'][$token]));
84
85 // ensure the token has been destroyed
86 $this->assertFalse($sessionManager->checkToken($token));
87 }
88
89 /**
90 * Check an invalid session token
91 */
92 public function testCheckInvalidToken()
93 {
94 $session = [];
95 $sessionManager = new SessionManager($session, self::$conf);
96
97 $this->assertFalse($sessionManager->checkToken('4dccc3a45ad9d03e5542b90c37d8db6d10f2b38b'));
98 }
99
100 /**
101 * Test SessionManager::checkId with a valid ID - TEST ALL THE HASHES!
102 *
103 * This tests extensively covers all hash algorithms / bit representations
104 */
105 public function testIsAnyHashSessionIdValid()
106 {
107 foreach (self::$sidHashes as $algo => $bpcs) {
108 foreach ($bpcs as $bpc => $hash) {
109 $this->assertTrue(SessionManager::checkId($hash));
110 }
111 }
112 }
113
114 /**
115 * Test checkId with a valid ID - SHA-1 hashes
116 */
117 public function testIsSha1SessionIdValid()
118 {
119 $this->assertTrue(SessionManager::checkId(sha1('shaarli')));
120 }
121
122 /**
123 * Test checkId with a valid ID - SHA-256 hashes
124 */
125 public function testIsSha256SessionIdValid()
126 {
127 $this->assertTrue(SessionManager::checkId(hash('sha256', 'shaarli')));
128 }
129
130 /**
131 * Test checkId with a valid ID - SHA-512 hashes
132 */
133 public function testIsSha512SessionIdValid()
134 {
135 $this->assertTrue(SessionManager::checkId(hash('sha512', 'shaarli')));
136 }
137
138 /**
139 * Test checkId with invalid IDs.
140 */
141 public function testIsSessionIdInvalid()
142 {
143 $this->assertFalse(SessionManager::checkId(''));
144 $this->assertFalse(SessionManager::checkId([]));
145 $this->assertFalse(
146 SessionManager::checkId('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=')
147 );
148 }
149}
diff --git a/tests/ThemeUtilsTest.php b/tests/ThemeUtilsTest.php
new file mode 100644
index 00000000..e44564be
--- /dev/null
+++ b/tests/ThemeUtilsTest.php
@@ -0,0 +1,55 @@
1<?php
2
3namespace Shaarli;
4
5/**
6 * Class ThemeUtilsTest
7 *
8 * @package Shaarli
9 */
10class ThemeUtilsTest extends \PHPUnit_Framework_TestCase
11{
12 /**
13 * Test getThemes() with existing theme directories.
14 */
15 public function testGetThemes()
16 {
17 $themes = ['theme1', 'default', 'Bl1p_- bL0p'];
18 foreach ($themes as $theme) {
19 mkdir('sandbox/tpl/'. $theme, 0755, true);
20 }
21
22 // include a file which should be ignored
23 touch('sandbox/tpl/supertheme');
24
25 $res = ThemeUtils::getThemes('sandbox/tpl/');
26 foreach ($res as $theme) {
27 $this->assertTrue(in_array($theme, $themes));
28 }
29 $this->assertFalse(in_array('supertheme', $res));
30
31 foreach ($themes as $theme) {
32 rmdir('sandbox/tpl/'. $theme);
33 }
34 unlink('sandbox/tpl/supertheme');
35 rmdir('sandbox/tpl');
36 }
37
38 /**
39 * Test getThemes() without any theme dir.
40 */
41 public function testGetThemesEmpty()
42 {
43 mkdir('sandbox/tpl/', 0755, true);
44 $this->assertEquals([], ThemeUtils::getThemes('sandbox/tpl/'));
45 rmdir('sandbox/tpl/');
46 }
47
48 /**
49 * Test getThemes() with an invalid path.
50 */
51 public function testGetThemesInvalid()
52 {
53 $this->assertEquals([], ThemeUtils::getThemes('nope'));
54 }
55}
diff --git a/tests/TimeZoneTest.php b/tests/TimeZoneTest.php
index 2976d116..127fdc19 100644
--- a/tests/TimeZoneTest.php
+++ b/tests/TimeZoneTest.php
@@ -11,24 +11,45 @@ require_once 'application/TimeZone.php';
11class TimeZoneTest extends PHPUnit_Framework_TestCase 11class TimeZoneTest extends PHPUnit_Framework_TestCase
12{ 12{
13 /** 13 /**
14 * @var array of timezones
15 */
16 protected $installedTimezones;
17
18 public function setUp()
19 {
20 $this->installedTimezones = [
21 'Antarctica/Syowa',
22 'Europe/London',
23 'Europe/Paris',
24 'UTC'
25 ];
26 }
27
28 /**
14 * Generate a timezone selection form 29 * Generate a timezone selection form
15 */ 30 */
16 public function testGenerateTimeZoneForm() 31 public function testGenerateTimeZoneForm()
17 { 32 {
18 $generated = generateTimeZoneForm(); 33 $expected = [
34 'continents' => [
35 'Antarctica',
36 'Europe',
37 'UTC',
38 'selected' => '',
39 ],
40 'cities' => [
41 ['continent' => 'Antarctica', 'city' => 'Syowa'],
42 ['continent' => 'Europe', 'city' => 'London'],
43 ['continent' => 'Europe', 'city' => 'Paris'],
44 ['continent' => 'UTC', 'city' => 'UTC'],
45 'selected' => '',
46 ]
47 ];
19 48
20 // HTML form 49 list($continents, $cities) = generateTimeZoneData($this->installedTimezones);
21 $this->assertStringStartsWith('Continent:<select', $generated[0]);
22 $this->assertContains('selected="selected"', $generated[0]);
23 $this->assertStringEndsWith('</select><br />', $generated[0]);
24 50
25 // Javascript handler 51 $this->assertEquals($expected['continents'], $continents);
26 $this->assertStringStartsWith('<script>', $generated[1]); 52 $this->assertEquals($expected['cities'], $cities);
27 $this->assertContains(
28 '<option value=\"Bermuda\">Bermuda<\/option>',
29 $generated[1]
30 );
31 $this->assertStringEndsWith('</script>', $generated[1]);
32 } 53 }
33 54
34 /** 55 /**
@@ -36,28 +57,26 @@ class TimeZoneTest extends PHPUnit_Framework_TestCase
36 */ 57 */
37 public function testGenerateTimeZoneFormPreselected() 58 public function testGenerateTimeZoneFormPreselected()
38 { 59 {
39 $generated = generateTimeZoneForm('Antarctica/Syowa'); 60 $expected = [
40 61 'continents' => [
41 // HTML form 62 'Antarctica',
42 $this->assertStringStartsWith('Continent:<select', $generated[0]); 63 'Europe',
43 $this->assertContains( 64 'UTC',
44 'value="Antarctica" selected="selected"', 65 'selected' => 'Antarctica',
45 $generated[0] 66 ],
46 ); 67 'cities' => [
47 $this->assertContains( 68 ['continent' => 'Antarctica', 'city' => 'Syowa'],
48 'value="Syowa" selected="selected"', 69 ['continent' => 'Europe', 'city' => 'London'],
49 $generated[0] 70 ['continent' => 'Europe', 'city' => 'Paris'],
50 ); 71 ['continent' => 'UTC', 'city' => 'UTC'],
51 $this->assertStringEndsWith('</select><br />', $generated[0]); 72 'selected' => 'Syowa',
73 ]
74 ];
52 75
76 list($continents, $cities) = generateTimeZoneData($this->installedTimezones, 'Antarctica/Syowa');
53 77
54 // Javascript handler 78 $this->assertEquals($expected['continents'], $continents);
55 $this->assertStringStartsWith('<script>', $generated[1]); 79 $this->assertEquals($expected['cities'], $cities);
56 $this->assertContains(
57 '<option value=\"Bermuda\">Bermuda<\/option>',
58 $generated[1]
59 );
60 $this->assertStringEndsWith('</script>', $generated[1]);
61 } 80 }
62 81
63 /** 82 /**
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php
index a3e8a4d2..77578528 100644
--- a/tests/Updater/UpdaterTest.php
+++ b/tests/Updater/UpdaterTest.php
@@ -1,7 +1,10 @@
1<?php 1<?php
2use Shaarli\Config\ConfigJson;
3use Shaarli\Config\ConfigManager;
4use Shaarli\Config\ConfigPhp;
2 5
3require_once 'application/config/ConfigManager.php';
4require_once 'tests/Updater/DummyUpdater.php'; 6require_once 'tests/Updater/DummyUpdater.php';
7require_once 'inc/rain.tpl.class.php';
5 8
6/** 9/**
7 * Class UpdaterTest. 10 * Class UpdaterTest.
@@ -271,7 +274,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
271 public function testEscapeConfig() 274 public function testEscapeConfig()
272 { 275 {
273 $sandbox = 'sandbox/config'; 276 $sandbox = 'sandbox/config';
274 copy(self::$configFile .'.json.php', $sandbox .'.json.php'); 277 copy(self::$configFile . '.json.php', $sandbox . '.json.php');
275 $this->conf = new ConfigManager($sandbox); 278 $this->conf = new ConfigManager($sandbox);
276 $title = '<script>alert("title");</script>'; 279 $title = '<script>alert("title");</script>';
277 $headerLink = '<script>alert("header_link");</script>'; 280 $headerLink = '<script>alert("header_link");</script>';
@@ -286,7 +289,43 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
286 $this->assertEquals(escape($title), $this->conf->get('general.title')); 289 $this->assertEquals(escape($title), $this->conf->get('general.title'));
287 $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link')); 290 $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link'));
288 $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url')); 291 $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url'));
289 unlink($sandbox .'.json.php'); 292 unlink($sandbox . '.json.php');
293 }
294
295 /**
296 * Test updateMethodApiSettings(): create default settings for the API (enabled + secret).
297 */
298 public function testUpdateApiSettings()
299 {
300 $confFile = 'sandbox/config';
301 copy(self::$configFile .'.json.php', $confFile .'.json.php');
302 $conf = new ConfigManager($confFile);
303 $updater = new Updater(array(), array(), $conf, true);
304
305 $this->assertFalse($conf->exists('api.enabled'));
306 $this->assertFalse($conf->exists('api.secret'));
307 $updater->updateMethodApiSettings();
308 $conf->reload();
309 $this->assertTrue($conf->get('api.enabled'));
310 $this->assertTrue($conf->exists('api.secret'));
311 unlink($confFile .'.json.php');
312 }
313
314 /**
315 * Test updateMethodApiSettings(): already set, do nothing.
316 */
317 public function testUpdateApiSettingsNothingToDo()
318 {
319 $confFile = 'sandbox/config';
320 copy(self::$configFile .'.json.php', $confFile .'.json.php');
321 $conf = new ConfigManager($confFile);
322 $conf->set('api.enabled', false);
323 $conf->set('api.secret', '');
324 $updater = new Updater(array(), array(), $conf, true);
325 $updater->updateMethodApiSettings();
326 $this->assertFalse($conf->get('api.enabled'));
327 $this->assertEmpty($conf->get('api.secret'));
328 unlink($confFile .'.json.php');
290 } 329 }
291 330
292 /** 331 /**
@@ -387,6 +426,50 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
387 } 426 }
388 427
389 /** 428 /**
429 * Test defaultTheme update with default settings: nothing to do.
430 */
431 public function testDefaultThemeWithDefaultSettings()
432 {
433 $sandbox = 'sandbox/config';
434 copy(self::$configFile . '.json.php', $sandbox . '.json.php');
435 $this->conf = new ConfigManager($sandbox);
436 $updater = new Updater([], [], $this->conf, true);
437 $this->assertTrue($updater->updateMethodDefaultTheme());
438
439 $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl'));
440 $this->assertEquals('default', $this->conf->get('resource.theme'));
441 $this->conf = new ConfigManager($sandbox);
442 $this->assertEquals('tpl/', $this->conf->get('resource.raintpl_tpl'));
443 $this->assertEquals('default', $this->conf->get('resource.theme'));
444 unlink($sandbox . '.json.php');
445 }
446
447 /**
448 * Test defaultTheme update with a custom theme in a subfolder
449 */
450 public function testDefaultThemeWithCustomTheme()
451 {
452 $theme = 'iamanartist';
453 $sandbox = 'sandbox/config';
454 copy(self::$configFile . '.json.php', $sandbox . '.json.php');
455 $this->conf = new ConfigManager($sandbox);
456 mkdir('sandbox/'. $theme);
457 touch('sandbox/'. $theme .'/linklist.html');
458 $this->conf->set('resource.raintpl_tpl', 'sandbox/'. $theme .'/');
459 $updater = new Updater([], [], $this->conf, true);
460 $this->assertTrue($updater->updateMethodDefaultTheme());
461
462 $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl'));
463 $this->assertEquals($theme, $this->conf->get('resource.theme'));
464 $this->conf = new ConfigManager($sandbox);
465 $this->assertEquals('sandbox', $this->conf->get('resource.raintpl_tpl'));
466 $this->assertEquals($theme, $this->conf->get('resource.theme'));
467 unlink($sandbox . '.json.php');
468 unlink('sandbox/'. $theme .'/linklist.html');
469 rmdir('sandbox/'. $theme);
470 }
471
472 /**
390 * Test updateMethodEscapeMarkdown with markdown plugin enabled 473 * Test updateMethodEscapeMarkdown with markdown plugin enabled
391 * => setting markdown_escape set to false. 474 * => setting markdown_escape set to false.
392 */ 475 */
@@ -396,8 +479,8 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
396 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); 479 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
397 $this->conf = new ConfigManager($sandboxConf); 480 $this->conf = new ConfigManager($sandboxConf);
398 481
399 $this->conf->set('general.enabled_plugins', array('markdown')); 482 $this->conf->set('general.enabled_plugins', ['markdown']);
400 $updater = new Updater(array(), array(), $this->conf, true); 483 $updater = new Updater([], [], $this->conf, true);
401 $this->assertTrue($updater->updateMethodEscapeMarkdown()); 484 $this->assertTrue($updater->updateMethodEscapeMarkdown());
402 $this->assertFalse($this->conf->get('security.markdown_escape')); 485 $this->assertFalse($this->conf->get('security.markdown_escape'));
403 486
@@ -416,8 +499,8 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
416 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); 499 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
417 $this->conf = new ConfigManager($sandboxConf); 500 $this->conf = new ConfigManager($sandboxConf);
418 501
419 $this->conf->set('general.enabled_plugins', array()); 502 $this->conf->set('general.enabled_plugins', []);
420 $updater = new Updater(array(), array(), $this->conf, true); 503 $updater = new Updater([], [], $this->conf, true);
421 $this->assertTrue($updater->updateMethodEscapeMarkdown()); 504 $this->assertTrue($updater->updateMethodEscapeMarkdown());
422 $this->assertTrue($this->conf->get('security.markdown_escape')); 505 $this->assertTrue($this->conf->get('security.markdown_escape'));
423 506
@@ -435,7 +518,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
435 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php'); 518 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
436 $this->conf = new ConfigManager($sandboxConf); 519 $this->conf = new ConfigManager($sandboxConf);
437 $this->conf->set('security.markdown_escape', true); 520 $this->conf->set('security.markdown_escape', true);
438 $updater = new Updater(array(), array(), $this->conf, true); 521 $updater = new Updater([], [], $this->conf, true);
439 $this->assertTrue($updater->updateMethodEscapeMarkdown()); 522 $this->assertTrue($updater->updateMethodEscapeMarkdown());
440 $this->assertTrue($this->conf->get('security.markdown_escape')); 523 $this->assertTrue($this->conf->get('security.markdown_escape'));
441 } 524 }
@@ -446,8 +529,94 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
446 public function testEscapeMarkdownSettingNothingToDoDisabled() 529 public function testEscapeMarkdownSettingNothingToDoDisabled()
447 { 530 {
448 $this->conf->set('security.markdown_escape', false); 531 $this->conf->set('security.markdown_escape', false);
449 $updater = new Updater(array(), array(), $this->conf, true); 532 $updater = new Updater([], [], $this->conf, true);
450 $this->assertTrue($updater->updateMethodEscapeMarkdown()); 533 $this->assertTrue($updater->updateMethodEscapeMarkdown());
451 $this->assertFalse($this->conf->get('security.markdown_escape')); 534 $this->assertFalse($this->conf->get('security.markdown_escape'));
452 } 535 }
536
537 /**
538 * Test updateMethodPiwikUrl with valid data
539 */
540 public function testUpdatePiwikUrlValid()
541 {
542 $sandboxConf = 'sandbox/config';
543 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
544 $this->conf = new ConfigManager($sandboxConf);
545 $url = 'mypiwik.tld';
546 $this->conf->set('plugins.PIWIK_URL', $url);
547 $updater = new Updater([], [], $this->conf, true);
548 $this->assertTrue($updater->updateMethodPiwikUrl());
549 $this->assertEquals('http://'. $url, $this->conf->get('plugins.PIWIK_URL'));
550
551 // reload from file
552 $this->conf = new ConfigManager($sandboxConf);
553 $this->assertEquals('http://'. $url, $this->conf->get('plugins.PIWIK_URL'));
554 }
555
556 /**
557 * Test updateMethodPiwikUrl without setting
558 */
559 public function testUpdatePiwikUrlEmpty()
560 {
561 $updater = new Updater([], [], $this->conf, true);
562 $this->assertTrue($updater->updateMethodPiwikUrl());
563 $this->assertEmpty($this->conf->get('plugins.PIWIK_URL'));
564 }
565
566 /**
567 * Test updateMethodPiwikUrl: valid URL, nothing to do
568 */
569 public function testUpdatePiwikUrlNothingToDo()
570 {
571 $url = 'https://mypiwik.tld';
572 $this->conf->set('plugins.PIWIK_URL', $url);
573 $updater = new Updater([], [], $this->conf, true);
574 $this->assertTrue($updater->updateMethodPiwikUrl());
575 $this->assertEquals($url, $this->conf->get('plugins.PIWIK_URL'));
576 }
577
578 /**
579 * Test updateMethodAtomDefault with show_atom set to false
580 * => update to true.
581 */
582 public function testUpdateMethodAtomDefault()
583 {
584 $sandboxConf = 'sandbox/config';
585 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
586 $this->conf = new ConfigManager($sandboxConf);
587 $this->conf->set('feed.show_atom', false);
588 $updater = new Updater([], [], $this->conf, true);
589 $this->assertTrue($updater->updateMethodAtomDefault());
590 $this->assertTrue($this->conf->get('feed.show_atom'));
591 // reload from file
592 $this->conf = new ConfigManager($sandboxConf);
593 $this->assertTrue($this->conf->get('feed.show_atom'));
594 }
595 /**
596 * Test updateMethodAtomDefault with show_atom not set.
597 * => nothing to do
598 */
599 public function testUpdateMethodAtomDefaultNoExist()
600 {
601 $sandboxConf = 'sandbox/config';
602 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
603 $this->conf = new ConfigManager($sandboxConf);
604 $updater = new Updater([], [], $this->conf, true);
605 $this->assertTrue($updater->updateMethodAtomDefault());
606 $this->assertTrue($this->conf->get('feed.show_atom'));
607 }
608 /**
609 * Test updateMethodAtomDefault with show_atom set to true.
610 * => nothing to do
611 */
612 public function testUpdateMethodAtomDefaultAlreadyTrue()
613 {
614 $sandboxConf = 'sandbox/config';
615 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
616 $this->conf = new ConfigManager($sandboxConf);
617 $this->conf->set('feed.show_atom', true);
618 $updater = new Updater([], [], $this->conf, true);
619 $this->assertTrue($updater->updateMethodAtomDefault());
620 $this->assertTrue($this->conf->get('feed.show_atom'));
621 }
453} 622}
diff --git a/tests/Url/CleanupUrlTest.php b/tests/Url/CleanupUrlTest.php
index ba9a0437..1407d7d2 100644
--- a/tests/Url/CleanupUrlTest.php
+++ b/tests/Url/CleanupUrlTest.php
@@ -8,7 +8,13 @@ require_once 'application/Url.php';
8class CleanupUrlTest extends PHPUnit_Framework_TestCase 8class CleanupUrlTest extends PHPUnit_Framework_TestCase
9{ 9{
10 /** 10 /**
11 * Clean empty UrlThanks for building nothing 11 * @var string reference URL
12 */
13 protected $ref = 'http://domain.tld:3000';
14
15
16 /**
17 * Clean empty URL
12 */ 18 */
13 public function testCleanupUrlEmpty() 19 public function testCleanupUrlEmpty()
14 { 20 {
@@ -16,59 +22,87 @@ class CleanupUrlTest extends PHPUnit_Framework_TestCase
16 } 22 }
17 23
18 /** 24 /**
19 * Clean an already cleaned Url 25 * Clean an already cleaned URL
20 */ 26 */
21 public function testCleanupUrlAlreadyClean() 27 public function testCleanupUrlAlreadyClean()
22 { 28 {
23 $ref = 'http://domain.tld:3000'; 29 $this->assertEquals($this->ref, cleanup_url($this->ref));
24 $this->assertEquals($ref, cleanup_url($ref)); 30 $this->ref2 = $this->ref.'/path/to/dir/';
25 $ref = $ref.'/path/to/dir/'; 31 $this->assertEquals($this->ref2, cleanup_url($this->ref2));
26 $this->assertEquals($ref, cleanup_url($ref)); 32 }
33
34 /**
35 * Clean URL fragments
36 */
37 public function testCleanupUrlFragment()
38 {
39 $this->assertEquals($this->ref, cleanup_url($this->ref.'#tk.rss_all'));
40 $this->assertEquals($this->ref, cleanup_url($this->ref.'#xtor=RSS-'));
41 $this->assertEquals($this->ref, cleanup_url($this->ref.'#xtor=RSS-U3ht0tkc4b'));
42 }
43
44 /**
45 * Clean URL query - single annoying parameter
46 */
47 public function testCleanupUrlQuerySingle()
48 {
49 $this->assertEquals($this->ref, cleanup_url($this->ref.'?action_object_map=junk'));
50 $this->assertEquals($this->ref, cleanup_url($this->ref.'?action_ref_map=Cr4p!'));
51 $this->assertEquals($this->ref, cleanup_url($this->ref.'?action_type_map=g4R84g3'));
52
53 $this->assertEquals($this->ref, cleanup_url($this->ref.'?fb_stuff=v41u3'));
54 $this->assertEquals($this->ref, cleanup_url($this->ref.'?fb=71m3w4573'));
55
56 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_campaign=zomg'));
57 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_medium=numnum'));
58 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_source=c0d3'));
59 $this->assertEquals($this->ref, cleanup_url($this->ref.'?utm_term=1n4l'));
60
61 $this->assertEquals($this->ref, cleanup_url($this->ref.'?xtor=some-url'));
62
63 $this->assertEquals($this->ref, cleanup_url($this->ref.'?campaign_name=junk'));
64 $this->assertEquals($this->ref, cleanup_url($this->ref.'?campaign_start=junk'));
65 $this->assertEquals($this->ref, cleanup_url($this->ref.'?campaign_item_index=junk'));
27 } 66 }
28 67
29 /** 68 /**
30 * Clean Url needing cleaning 69 * Clean URL query - multiple annoying parameters
31 */ 70 */
32 public function testCleanupUrlNeedClean() 71 public function testCleanupUrlQueryMultiple()
33 { 72 {
34 $ref = 'http://domain.tld:3000'; 73 $this->assertEquals($this->ref, cleanup_url($this->ref.'?xtor=some-url&fb=som3th1ng'));
35 $this->assertEquals($ref, cleanup_url($ref.'#tk.rss_all')); 74
36 $this->assertEquals($ref, cleanup_url($ref.'#xtor=RSS-')); 75 $this->assertEquals($this->ref, cleanup_url(
37 $this->assertEquals($ref, cleanup_url($ref.'#xtor=RSS-U3ht0tkc4b')); 76 $this->ref.'?fb=stuff&utm_campaign=zomg&utm_medium=numnum&utm_source=c0d3'
38 $this->assertEquals($ref, cleanup_url($ref.'?action_object_map=junk'));
39 $this->assertEquals($ref, cleanup_url($ref.'?action_ref_map=Cr4p!'));
40 $this->assertEquals($ref, cleanup_url($ref.'?action_type_map=g4R84g3'));
41
42 $this->assertEquals($ref, cleanup_url($ref.'?fb_stuff=v41u3'));
43 $this->assertEquals($ref, cleanup_url($ref.'?fb=71m3w4573'));
44
45 $this->assertEquals($ref, cleanup_url($ref.'?utm_campaign=zomg'));
46 $this->assertEquals($ref, cleanup_url($ref.'?utm_medium=numnum'));
47 $this->assertEquals($ref, cleanup_url($ref.'?utm_source=c0d3'));
48 $this->assertEquals($ref, cleanup_url($ref.'?utm_term=1n4l'));
49
50 $this->assertEquals($ref, cleanup_url($ref.'?xtor=some-url'));
51 $this->assertEquals($ref, cleanup_url($ref.'?xtor=some-url&fb=som3th1ng'));
52 $this->assertEquals($ref, cleanup_url(
53 $ref.'?fb=stuff&utm_campaign=zomg&utm_medium=numnum&utm_source=c0d3'
54 )); 77 ));
55 $this->assertEquals($ref, cleanup_url( 78
56 $ref.'?xtor=some-url&fb=som3th1ng#tk.rss_all' 79 $this->assertEquals($this->ref, cleanup_url(
80 $this->ref.'?campaign_start=zomg&campaign_name=numnum'
81 ));
82 }
83
84 /**
85 * Clean URL query - multiple annoying parameters and fragment
86 */
87 public function testCleanupUrlQueryFragment()
88 {
89 $this->assertEquals($this->ref, cleanup_url(
90 $this->ref.'?xtor=some-url&fb=som3th1ng#tk.rss_all'
57 )); 91 ));
58 92
59 // ditch annoying query params and fragment, keep useful params 93 // ditch annoying query params and fragment, keep useful params
60 $this->assertEquals( 94 $this->assertEquals(
61 $ref.'?my=stuff&is=kept', 95 $this->ref.'?my=stuff&is=kept',
62 cleanup_url( 96 cleanup_url(
63 $ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#tk.rss_all' 97 $this->ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#tk.rss_all'
64 ) 98 )
65 ); 99 );
66 100
67 // ditch annoying query params, keep useful params and fragment 101 // ditch annoying query params, keep useful params and fragment
68 $this->assertEquals( 102 $this->assertEquals(
69 $ref.'?my=stuff&is=kept#again', 103 $this->ref.'?my=stuff&is=kept#again',
70 cleanup_url( 104 cleanup_url(
71 $ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#again' 105 $this->ref.'?fb=zomg&my=stuff&utm_medium=numnum&is=kept#again'
72 ) 106 )
73 ); 107 );
74 } 108 }
diff --git a/tests/Url/UrlTest.php b/tests/Url/UrlTest.php
index 05862372..aa2f2234 100644
--- a/tests/Url/UrlTest.php
+++ b/tests/Url/UrlTest.php
@@ -157,7 +157,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
157 /** 157 /**
158 * Test add trailing slash. 158 * Test add trailing slash.
159 */ 159 */
160 function testAddTrailingSlash() 160 public function testAddTrailingSlash()
161 { 161 {
162 $strOn = 'http://randomstr.com/test/'; 162 $strOn = 'http://randomstr.com/test/';
163 $strOff = 'http://randomstr.com/test'; 163 $strOff = 'http://randomstr.com/test';
@@ -168,7 +168,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
168 /** 168 /**
169 * Test valid HTTP url. 169 * Test valid HTTP url.
170 */ 170 */
171 function testUrlIsHttp() 171 public function testUrlIsHttp()
172 { 172 {
173 $url = new Url(self::$baseUrl); 173 $url = new Url(self::$baseUrl);
174 $this->assertTrue($url->isHttp()); 174 $this->assertTrue($url->isHttp());
@@ -177,7 +177,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
177 /** 177 /**
178 * Test non HTTP url. 178 * Test non HTTP url.
179 */ 179 */
180 function testUrlIsNotHttp() 180 public function testUrlIsNotHttp()
181 { 181 {
182 $url = new Url('ftp://save.tld/mysave'); 182 $url = new Url('ftp://save.tld/mysave');
183 $this->assertFalse($url->isHttp()); 183 $this->assertFalse($url->isHttp());
@@ -186,7 +186,7 @@ class UrlTest extends PHPUnit_Framework_TestCase
186 /** 186 /**
187 * Test International Domain Name to ASCII conversion 187 * Test International Domain Name to ASCII conversion
188 */ 188 */
189 function testIdnToAscii() 189 public function testIdnToAscii()
190 { 190 {
191 $ind = 'http://www.académie-française.fr/'; 191 $ind = 'http://www.académie-française.fr/';
192 $expected = 'http://www.xn--acadmie-franaise-npb1a.fr/'; 192 $expected = 'http://www.xn--acadmie-franaise-npb1a.fr/';
diff --git a/tests/Url/WhitelistProtocolsTest.php b/tests/Url/WhitelistProtocolsTest.php
new file mode 100644
index 00000000..a3156804
--- /dev/null
+++ b/tests/Url/WhitelistProtocolsTest.php
@@ -0,0 +1,63 @@
1<?php
2
3require_once 'application/Url.php';
4
5use Shaarli\Config\ConfigManager;
6
7/**
8 * Class WhitelistProtocolsTest
9 *
10 * Test whitelist_protocols() function of Url.
11 */
12class WhitelistProtocolsTest extends PHPUnit_Framework_TestCase
13{
14 /**
15 * Test whitelist_protocols() on a note (relative URL).
16 */
17 public function testWhitelistProtocolsRelative()
18 {
19 $whitelist = ['ftp', 'magnet'];
20 $url = '?12443564';
21 $this->assertEquals($url, whitelist_protocols($url, $whitelist));
22 $url = '/path.jpg';
23 $this->assertEquals($url, whitelist_protocols($url, $whitelist));
24 }
25
26 /**
27 * Test whitelist_protocols() on a note (relative URL).
28 */
29 public function testWhitelistProtocolMissing()
30 {
31 $whitelist = ['ftp', 'magnet'];
32 $url = 'test.tld/path/?query=value#hash';
33 $this->assertEquals('http://'. $url, whitelist_protocols($url, $whitelist));
34 }
35
36 /**
37 * Test whitelist_protocols() with allowed protocols.
38 */
39 public function testWhitelistAllowedProtocol()
40 {
41 $whitelist = ['ftp', 'magnet'];
42 $url = 'http://test.tld/path/?query=value#hash';
43 $this->assertEquals($url, whitelist_protocols($url, $whitelist));
44 $url = 'https://test.tld/path/?query=value#hash';
45 $this->assertEquals($url, whitelist_protocols($url, $whitelist));
46 $url = 'ftp://test.tld/path/?query=value#hash';
47 $this->assertEquals($url, whitelist_protocols($url, $whitelist));
48 $url = 'magnet:test.tld/path/?query=value#hash';
49 $this->assertEquals($url, whitelist_protocols($url, $whitelist));
50 }
51
52 /**
53 * Test whitelist_protocols() with allowed protocols.
54 */
55 public function testWhitelistDisallowedProtocol()
56 {
57 $whitelist = ['ftp', 'magnet'];
58 $url = 'javascript:alert("xss");';
59 $this->assertEquals('http://alert("xss");', whitelist_protocols($url, $whitelist));
60 $url = 'other://test.tld/path/?query=value#hash';
61 $this->assertEquals('http://test.tld/path/?query=value#hash', whitelist_protocols($url, $whitelist));
62 }
63}
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
index 6a7870c4..6cd37a7a 100644
--- a/tests/UtilsTest.php
+++ b/tests/UtilsTest.php
@@ -4,10 +4,7 @@
4 */ 4 */
5 5
6require_once 'application/Utils.php'; 6require_once 'application/Utils.php';
7require_once 'tests/utils/ReferenceSessionIdHashes.php'; 7require_once 'application/Languages.php';
8
9// Initialize reference data before PHPUnit starts a session
10ReferenceSessionIdHashes::genAllHashes();
11 8
12 9
13/** 10/**
@@ -15,22 +12,33 @@ ReferenceSessionIdHashes::genAllHashes();
15 */ 12 */
16class UtilsTest extends PHPUnit_Framework_TestCase 13class UtilsTest extends PHPUnit_Framework_TestCase
17{ 14{
18 // Session ID hashes
19 protected static $sidHashes = null;
20
21 // Log file 15 // Log file
22 protected static $testLogFile = 'tests.log'; 16 protected static $testLogFile = 'tests.log';
23 17
24 // Expected log date format 18 // Expected log date format
25 protected static $dateFormat = 'Y/m/d H:i:s'; 19 protected static $dateFormat = 'Y/m/d H:i:s';
26 20
21 /**
22 * @var string Save the current timezone.
23 */
24 protected static $defaultTimeZone;
27 25
28 /** 26 /**
29 * Assign reference data 27 * Assign reference data
30 */ 28 */
31 public static function setUpBeforeClass() 29 public static function setUpBeforeClass()
32 { 30 {
33 self::$sidHashes = ReferenceSessionIdHashes::getHashes(); 31 self::$defaultTimeZone = date_default_timezone_get();
32 // Timezone without DST for test consistency
33 date_default_timezone_set('Africa/Nairobi');
34 }
35
36 /**
37 * Reset the timezone
38 */
39 public static function tearDownAfterClass()
40 {
41 date_default_timezone_set(self::$defaultTimeZone);
34 } 42 }
35 43
36 /** 44 /**
@@ -204,53 +212,263 @@ class UtilsTest extends PHPUnit_Framework_TestCase
204 $this->assertEquals('?', generateLocation($ref, 'localhost')); 212 $this->assertEquals('?', generateLocation($ref, 'localhost'));
205 } 213 }
206 214
215
207 /** 216 /**
208 * Test is_session_id_valid with a valid ID - TEST ALL THE HASHES! 217 * Test generateSecretApi.
209 *
210 * This tests extensively covers all hash algorithms / bit representations
211 */ 218 */
212 public function testIsAnyHashSessionIdValid() 219 public function testGenerateSecretApi()
213 { 220 {
214 foreach (self::$sidHashes as $algo => $bpcs) { 221 $this->assertEquals(12, strlen(generate_api_secret('foo', 'bar')));
215 foreach ($bpcs as $bpc => $hash) {
216 $this->assertTrue(is_session_id_valid($hash));
217 }
218 }
219 } 222 }
220 223
221 /** 224 /**
222 * Test is_session_id_valid with a valid ID - SHA-1 hashes 225 * Test generateSecretApi with invalid parameters.
223 */ 226 */
224 public function testIsSha1SessionIdValid() 227 public function testGenerateSecretApiInvalid()
225 { 228 {
226 $this->assertTrue(is_session_id_valid(sha1('shaarli'))); 229 $this->assertFalse(generate_api_secret('', ''));
230 $this->assertFalse(generate_api_secret(false, false));
227 } 231 }
228 232
229 /** 233 /**
230 * Test is_session_id_valid with a valid ID - SHA-256 hashes 234 * Test normalize_spaces.
231 */ 235 */
232 public function testIsSha256SessionIdValid() 236 public function testNormalizeSpace()
233 { 237 {
234 $this->assertTrue(is_session_id_valid(hash('sha256', 'shaarli'))); 238 $str = ' foo bar is important ';
239 $this->assertEquals('foo bar is important', normalize_spaces($str));
240 $this->assertEquals('foo', normalize_spaces('foo'));
241 $this->assertEquals('', normalize_spaces(''));
242 $this->assertEquals(null, normalize_spaces(null));
235 } 243 }
236 244
237 /** 245 /**
238 * Test is_session_id_valid with a valid ID - SHA-512 hashes 246 * Test arrays_combine
239 */ 247 */
240 public function testIsSha512SessionIdValid() 248 public function testCartesianProductGenerator()
241 { 249 {
242 $this->assertTrue(is_session_id_valid(hash('sha512', 'shaarli'))); 250 $arr = [['ab', 'cd'], ['ef', 'gh'], ['ij', 'kl'], ['m']];
251 $expected = [
252 ['ab', 'ef', 'ij', 'm'],
253 ['ab', 'ef', 'kl', 'm'],
254 ['ab', 'gh', 'ij', 'm'],
255 ['ab', 'gh', 'kl', 'm'],
256 ['cd', 'ef', 'ij', 'm'],
257 ['cd', 'ef', 'kl', 'm'],
258 ['cd', 'gh', 'ij', 'm'],
259 ['cd', 'gh', 'kl', 'm'],
260 ];
261 $this->assertEquals($expected, iterator_to_array(cartesian_product_generator($arr)));
243 } 262 }
244 263
245 /** 264 /**
246 * Test is_session_id_valid with invalid IDs. 265 * Test date_format() with invalid parameter.
247 */ 266 */
248 public function testIsSessionIdInvalid() 267 public function testDateFormatInvalid()
249 { 268 {
250 $this->assertFalse(is_session_id_valid('')); 269 $this->assertFalse(format_date([]));
251 $this->assertFalse(is_session_id_valid(array())); 270 $this->assertFalse(format_date(null));
252 $this->assertFalse( 271 }
253 is_session_id_valid('c0ZqcWF3VFE2NmJBdm1HMVQ0ZHJ3UmZPbTFsNGhkNHI=') 272
254 ); 273 /**
274 * Test is_integer_mixed with valid values
275 */
276 public function testIsIntegerMixedValid()
277 {
278 $this->assertTrue(is_integer_mixed(12));
279 $this->assertTrue(is_integer_mixed('12'));
280 $this->assertTrue(is_integer_mixed(-12));
281 $this->assertTrue(is_integer_mixed('-12'));
282 $this->assertTrue(is_integer_mixed(0));
283 $this->assertTrue(is_integer_mixed('0'));
284 $this->assertTrue(is_integer_mixed(0x0a));
285 }
286
287 /**
288 * Test is_integer_mixed with invalid values
289 */
290 public function testIsIntegerMixedInvalid()
291 {
292 $this->assertFalse(is_integer_mixed(true));
293 $this->assertFalse(is_integer_mixed(false));
294 $this->assertFalse(is_integer_mixed([]));
295 $this->assertFalse(is_integer_mixed(['test']));
296 $this->assertFalse(is_integer_mixed([12]));
297 $this->assertFalse(is_integer_mixed(new DateTime()));
298 $this->assertFalse(is_integer_mixed('0x0a'));
299 $this->assertFalse(is_integer_mixed('12k'));
300 $this->assertFalse(is_integer_mixed('k12'));
301 $this->assertFalse(is_integer_mixed(''));
302 }
303
304 /**
305 * Test return_bytes
306 */
307 public function testReturnBytes()
308 {
309 $this->assertEquals(2 * 1024, return_bytes('2k'));
310 $this->assertEquals(2 * 1024, return_bytes('2K'));
311 $this->assertEquals(2 * (pow(1024, 2)), return_bytes('2m'));
312 $this->assertEquals(2 * (pow(1024, 2)), return_bytes('2M'));
313 $this->assertEquals(2 * (pow(1024, 3)), return_bytes('2g'));
314 $this->assertEquals(2 * (pow(1024, 3)), return_bytes('2G'));
315 $this->assertEquals(374, return_bytes('374'));
316 $this->assertEquals(374, return_bytes(374));
317 $this->assertEquals(0, return_bytes('0'));
318 $this->assertEquals(0, return_bytes(0));
319 $this->assertEquals(-1, return_bytes('-1'));
320 $this->assertEquals(-1, return_bytes(-1));
321 $this->assertEquals('', return_bytes(''));
322 }
323
324 /**
325 * Test human_bytes
326 */
327 public function testHumanBytes()
328 {
329 $this->assertEquals('2'. t('kiB'), human_bytes(2 * 1024));
330 $this->assertEquals('2'. t('kiB'), human_bytes(strval(2 * 1024)));
331 $this->assertEquals('2'. t('MiB'), human_bytes(2 * (pow(1024, 2))));
332 $this->assertEquals('2'. t('MiB'), human_bytes(strval(2 * (pow(1024, 2)))));
333 $this->assertEquals('2'. t('GiB'), human_bytes(2 * (pow(1024, 3))));
334 $this->assertEquals('2'. t('GiB'), human_bytes(strval(2 * (pow(1024, 3)))));
335 $this->assertEquals('374'. t('B'), human_bytes(374));
336 $this->assertEquals('374'. t('B'), human_bytes('374'));
337 $this->assertEquals('232'. t('kiB'), human_bytes(237481));
338 $this->assertEquals(t('Unlimited'), human_bytes('0'));
339 $this->assertEquals(t('Unlimited'), human_bytes(0));
340 $this->assertEquals(t('Setting not set'), human_bytes(''));
341 }
342
343 /**
344 * Test get_max_upload_size with formatting
345 */
346 public function testGetMaxUploadSize()
347 {
348 $this->assertEquals('1'. t('MiB'), get_max_upload_size(2097152, '1024k'));
349 $this->assertEquals('1'. t('MiB'), get_max_upload_size('1m', '2m'));
350 $this->assertEquals('100'. t('B'), get_max_upload_size(100, 100));
351 }
352
353 /**
354 * Test get_max_upload_size without formatting
355 */
356 public function testGetMaxUploadSizeRaw()
357 {
358 $this->assertEquals('1048576', get_max_upload_size(2097152, '1024k', false));
359 $this->assertEquals('1048576', get_max_upload_size('1m', '2m', false));
360 $this->assertEquals('100', get_max_upload_size(100, 100, false));
361 }
362
363 /**
364 * Test alphabetical_sort by value, not reversed, with php-intl.
365 */
366 public function testAlphabeticalSortByValue()
367 {
368 $arr = [
369 'zZz',
370 'éee',
371 'éae',
372 'eee',
373 'A',
374 'a',
375 'zzz',
376 ];
377 $expected = [
378 'a',
379 'A',
380 'éae',
381 'eee',
382 'éee',
383 'zzz',
384 'zZz',
385 ];
386
387 alphabetical_sort($arr);
388 $this->assertEquals($expected, $arr);
389 }
390
391 /**
392 * Test alphabetical_sort by value, reversed, with php-intl.
393 */
394 public function testAlphabeticalSortByValueReversed()
395 {
396 $arr = [
397 'zZz',
398 'éee',
399 'éae',
400 'eee',
401 'A',
402 'a',
403 'zzz',
404 ];
405 $expected = [
406 'zZz',
407 'zzz',
408 'éee',
409 'eee',
410 'éae',
411 'A',
412 'a',
413 ];
414
415 alphabetical_sort($arr, true);
416 $this->assertEquals($expected, $arr);
417 }
418
419 /**
420 * Test alphabetical_sort by keys, not reversed, with php-intl.
421 */
422 public function testAlphabeticalSortByKeys()
423 {
424 $arr = [
425 'zZz' => true,
426 'éee' => true,
427 'éae' => true,
428 'eee' => true,
429 'A' => true,
430 'a' => true,
431 'zzz' => true,
432 ];
433 $expected = [
434 'a' => true,
435 'A' => true,
436 'éae' => true,
437 'eee' => true,
438 'éee' => true,
439 'zzz' => true,
440 'zZz' => true,
441 ];
442
443 alphabetical_sort($arr, true, true);
444 $this->assertEquals($expected, $arr);
445 }
446
447 /**
448 * Test alphabetical_sort by keys, reversed, with php-intl.
449 */
450 public function testAlphabeticalSortByKeysReversed()
451 {
452 $arr = [
453 'zZz' => true,
454 'éee' => true,
455 'éae' => true,
456 'eee' => true,
457 'A' => true,
458 'a' => true,
459 'zzz' => true,
460 ];
461 $expected = [
462 'zZz' => true,
463 'zzz' => true,
464 'éee' => true,
465 'eee' => true,
466 'éae' => true,
467 'A' => true,
468 'a' => true,
469 ];
470
471 alphabetical_sort($arr, true, true);
472 $this->assertEquals($expected, $arr);
255 } 473 }
256} 474}
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
new file mode 100644
index 00000000..23a56b1c
--- /dev/null
+++ b/tests/api/ApiMiddlewareTest.php
@@ -0,0 +1,208 @@
1<?php
2namespace Shaarli\Api;
3
4use Shaarli\Config\ConfigManager;
5
6use Slim\Container;
7use Slim\Http\Environment;
8use Slim\Http\Request;
9use Slim\Http\Response;
10
11/**
12 * Class ApiMiddlewareTest
13 *
14 * Test the REST API Slim Middleware.
15 *
16 * Note that we can't test a valid use case here, because the middleware
17 * needs to call a valid controller/action during its execution.
18 *
19 * @package Api
20 */
21class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase
22{
23 /**
24 * @var string datastore to test write operations
25 */
26 protected static $testDatastore = 'sandbox/datastore.php';
27
28 /**
29 * @var \ConfigManager instance
30 */
31 protected $conf;
32
33 /**
34 * @var \ReferenceLinkDB instance.
35 */
36 protected $refDB = null;
37
38 /**
39 * @var Container instance.
40 */
41 protected $container;
42
43 /**
44 * Before every test, instantiate a new Api with its config, plugins and links.
45 */
46 public function setUp()
47 {
48 $this->conf = new ConfigManager('tests/utils/config/configJson.json.php');
49 $this->conf->set('api.secret', 'NapoleonWasALizard');
50
51 $this->refDB = new \ReferenceLinkDB();
52 $this->refDB->write(self::$testDatastore);
53
54 $this->container = new Container();
55 $this->container['conf'] = $this->conf;
56 }
57
58 /**
59 * After every test, remove the test datastore.
60 */
61 public function tearDown()
62 {
63 @unlink(self::$testDatastore);
64 }
65
66 /**
67 * Invoke the middleware with the API disabled:
68 * should return a 401 error Unauthorized.
69 */
70 public function testInvokeMiddlewareApiDisabled()
71 {
72 $this->conf->set('api.enabled', false);
73 $mw = new ApiMiddleware($this->container);
74 $env = Environment::mock([
75 'REQUEST_METHOD' => 'GET',
76 'REQUEST_URI' => '/echo',
77 ]);
78 $request = Request::createFromEnvironment($env);
79 $response = new Response();
80 /** @var Response $response */
81 $response = $mw($request, $response, null);
82
83 $this->assertEquals(401, $response->getStatusCode());
84 $body = json_decode((string) $response->getBody());
85 $this->assertEquals('Not authorized', $body);
86 }
87
88 /**
89 * Invoke the middleware with the API disabled in debug mode:
90 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
91 */
92 public function testInvokeMiddlewareApiDisabledDebug()
93 {
94 $this->conf->set('api.enabled', false);
95 $this->conf->set('dev.debug', true);
96 $mw = new ApiMiddleware($this->container);
97 $env = Environment::mock([
98 'REQUEST_METHOD' => 'GET',
99 'REQUEST_URI' => '/echo',
100 ]);
101 $request = Request::createFromEnvironment($env);
102 $response = new Response();
103 /** @var Response $response */
104 $response = $mw($request, $response, null);
105
106 $this->assertEquals(401, $response->getStatusCode());
107 $body = json_decode((string) $response->getBody());
108 $this->assertEquals('Not authorized: API is disabled', $body->message);
109 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
110 }
111
112 /**
113 * Invoke the middleware without a token (debug):
114 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
115 */
116 public function testInvokeMiddlewareNoTokenProvidedDebug()
117 {
118 $this->conf->set('dev.debug', true);
119 $mw = new ApiMiddleware($this->container);
120 $env = Environment::mock([
121 'REQUEST_METHOD' => 'GET',
122 'REQUEST_URI' => '/echo',
123 ]);
124 $request = Request::createFromEnvironment($env);
125 $response = new Response();
126 /** @var Response $response */
127 $response = $mw($request, $response, null);
128
129 $this->assertEquals(401, $response->getStatusCode());
130 $body = json_decode((string) $response->getBody());
131 $this->assertEquals('Not authorized: JWT token not provided', $body->message);
132 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
133 }
134
135 /**
136 * Invoke the middleware without a secret set in settings (debug):
137 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
138 */
139 public function testInvokeMiddlewareNoSecretSetDebug()
140 {
141 $this->conf->set('dev.debug', true);
142 $this->conf->set('api.secret', '');
143 $mw = new ApiMiddleware($this->container);
144 $env = Environment::mock([
145 'REQUEST_METHOD' => 'GET',
146 'REQUEST_URI' => '/echo',
147 'HTTP_AUTHORIZATION'=> 'Bearer jwt',
148 ]);
149 $request = Request::createFromEnvironment($env);
150 $response = new Response();
151 /** @var Response $response */
152 $response = $mw($request, $response, null);
153
154 $this->assertEquals(401, $response->getStatusCode());
155 $body = json_decode((string) $response->getBody());
156 $this->assertEquals('Not authorized: Token secret must be set in Shaarli\'s administration', $body->message);
157 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
158 }
159
160 /**
161 * Invoke the middleware with an invalid JWT token header
162 */
163 public function testInvalidJwtAuthHeaderDebug()
164 {
165 $this->conf->set('dev.debug', true);
166 $mw = new ApiMiddleware($this->container);
167 $env = Environment::mock([
168 'REQUEST_METHOD' => 'GET',
169 'REQUEST_URI' => '/echo',
170 'HTTP_AUTHORIZATION'=> 'PolarBearer jwt',
171 ]);
172 $request = Request::createFromEnvironment($env);
173 $response = new Response();
174 /** @var Response $response */
175 $response = $mw($request, $response, null);
176
177 $this->assertEquals(401, $response->getStatusCode());
178 $body = json_decode((string) $response->getBody());
179 $this->assertEquals('Not authorized: Invalid JWT header', $body->message);
180 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
181 }
182
183 /**
184 * Invoke the middleware with an invalid JWT token (debug):
185 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
186 *
187 * Note: specific JWT errors tests are handled in ApiUtilsTest.
188 */
189 public function testInvokeMiddlewareInvalidJwtDebug()
190 {
191 $this->conf->set('dev.debug', true);
192 $mw = new ApiMiddleware($this->container);
193 $env = Environment::mock([
194 'REQUEST_METHOD' => 'GET',
195 'REQUEST_URI' => '/echo',
196 'HTTP_AUTHORIZATION'=> 'Bearer jwt',
197 ]);
198 $request = Request::createFromEnvironment($env);
199 $response = new Response();
200 /** @var Response $response */
201 $response = $mw($request, $response, null);
202
203 $this->assertEquals(401, $response->getStatusCode());
204 $body = json_decode((string) $response->getBody());
205 $this->assertEquals('Not authorized: Malformed JWT token', $body->message);
206 $this->assertContains('ApiAuthorizationException', $body->stacktrace);
207 }
208}
diff --git a/tests/api/ApiUtilsTest.php b/tests/api/ApiUtilsTest.php
new file mode 100644
index 00000000..62baf4c5
--- /dev/null
+++ b/tests/api/ApiUtilsTest.php
@@ -0,0 +1,352 @@
1<?php
2
3namespace Shaarli\Api;
4
5use Shaarli\Base64Url;
6
7
8/**
9 * Class ApiUtilsTest
10 */
11class ApiUtilsTest extends \PHPUnit_Framework_TestCase
12{
13 /**
14 * Force the timezone for ISO datetimes.
15 */
16 public static function setUpBeforeClass()
17 {
18 date_default_timezone_set('UTC');
19 }
20
21 /**
22 * Generate a valid JWT token.
23 *
24 * @param string $secret API secret used to generate the signature.
25 *
26 * @return string Generated token.
27 */
28 public static function generateValidJwtToken($secret)
29 {
30 $header = Base64Url::encode('{
31 "typ": "JWT",
32 "alg": "HS512"
33 }');
34 $payload = Base64Url::encode('{
35 "iat": '. time() .'
36 }');
37 $signature = Base64Url::encode(hash_hmac('sha512', $header .'.'. $payload , $secret, true));
38 return $header .'.'. $payload .'.'. $signature;
39 }
40
41 /**
42 * Generate a JWT token from given header and payload.
43 *
44 * @param string $header Header in JSON format.
45 * @param string $payload Payload in JSON format.
46 * @param string $secret API secret used to hash the signature.
47 *
48 * @return string JWT token.
49 */
50 public static function generateCustomJwtToken($header, $payload, $secret)
51 {
52 $header = Base64Url::encode($header);
53 $payload = Base64Url::encode($payload);
54 $signature = Base64Url::encode(hash_hmac('sha512', $header . '.' . $payload, $secret, true));
55 return $header . '.' . $payload . '.' . $signature;
56 }
57
58 /**
59 * Test validateJwtToken() with a valid JWT token.
60 */
61 public function testValidateJwtTokenValid()
62 {
63 $secret = 'WarIsPeace';
64 ApiUtils::validateJwtToken(self::generateValidJwtToken($secret), $secret);
65 }
66
67 /**
68 * Test validateJwtToken() with a malformed JWT token.
69 *
70 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
71 * @expectedExceptionMessage Malformed JWT token
72 */
73 public function testValidateJwtTokenMalformed()
74 {
75 $token = 'ABC.DEF';
76 ApiUtils::validateJwtToken($token, 'foo');
77 }
78
79 /**
80 * Test validateJwtToken() with an empty JWT token.
81 *
82 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
83 * @expectedExceptionMessage Malformed JWT token
84 */
85 public function testValidateJwtTokenMalformedEmpty()
86 {
87 $token = false;
88 ApiUtils::validateJwtToken($token, 'foo');
89 }
90
91 /**
92 * Test validateJwtToken() with a JWT token without header.
93 *
94 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
95 * @expectedExceptionMessage Malformed JWT token
96 */
97 public function testValidateJwtTokenMalformedEmptyHeader()
98 {
99 $token = '.payload.signature';
100 ApiUtils::validateJwtToken($token, 'foo');
101 }
102
103 /**
104 * Test validateJwtToken() with a JWT token without payload
105 *
106 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
107 * @expectedExceptionMessage Malformed JWT token
108 */
109 public function testValidateJwtTokenMalformedEmptyPayload()
110 {
111 $token = 'header..signature';
112 ApiUtils::validateJwtToken($token, 'foo');
113 }
114
115 /**
116 * Test validateJwtToken() with a JWT token with an empty signature.
117 *
118 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
119 * @expectedExceptionMessage Invalid JWT signature
120 */
121 public function testValidateJwtTokenInvalidSignatureEmpty()
122 {
123 $token = 'header.payload.';
124 ApiUtils::validateJwtToken($token, 'foo');
125 }
126
127 /**
128 * Test validateJwtToken() with a JWT token with an invalid signature.
129 *
130 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
131 * @expectedExceptionMessage Invalid JWT signature
132 */
133 public function testValidateJwtTokenInvalidSignature()
134 {
135 $token = 'header.payload.nope';
136 ApiUtils::validateJwtToken($token, 'foo');
137 }
138
139 /**
140 * Test validateJwtToken() with a JWT token with a signature generated with the wrong API secret.
141 *
142 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
143 * @expectedExceptionMessage Invalid JWT signature
144 */
145 public function testValidateJwtTokenInvalidSignatureSecret()
146 {
147 ApiUtils::validateJwtToken(self::generateValidJwtToken('foo'), 'bar');
148 }
149
150 /**
151 * Test validateJwtToken() with a JWT token with a an invalid header (not JSON).
152 *
153 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
154 * @expectedExceptionMessage Invalid JWT header
155 */
156 public function testValidateJwtTokenInvalidHeader()
157 {
158 $token = $this->generateCustomJwtToken('notJSON', '{"JSON":1}', 'secret');
159 ApiUtils::validateJwtToken($token, 'secret');
160 }
161
162 /**
163 * Test validateJwtToken() with a JWT token with a an invalid payload (not JSON).
164 *
165 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
166 * @expectedExceptionMessage Invalid JWT payload
167 */
168 public function testValidateJwtTokenInvalidPayload()
169 {
170 $token = $this->generateCustomJwtToken('{"JSON":1}', 'notJSON', 'secret');
171 ApiUtils::validateJwtToken($token, 'secret');
172 }
173
174 /**
175 * Test validateJwtToken() with a JWT token without issued time.
176 *
177 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
178 * @expectedExceptionMessage Invalid JWT issued time
179 */
180 public function testValidateJwtTokenInvalidTimeEmpty()
181 {
182 $token = $this->generateCustomJwtToken('{"JSON":1}', '{"JSON":1}', 'secret');
183 ApiUtils::validateJwtToken($token, 'secret');
184 }
185
186 /**
187 * Test validateJwtToken() with an expired JWT token.
188 *
189 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
190 * @expectedExceptionMessage Invalid JWT issued time
191 */
192 public function testValidateJwtTokenInvalidTimeExpired()
193 {
194 $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() - 600) . '}', 'secret');
195 ApiUtils::validateJwtToken($token, 'secret');
196 }
197
198 /**
199 * Test validateJwtToken() with a JWT token issued in the future.
200 *
201 * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
202 * @expectedExceptionMessage Invalid JWT issued time
203 */
204 public function testValidateJwtTokenInvalidTimeFuture()
205 {
206 $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() + 60) . '}', 'secret');
207 ApiUtils::validateJwtToken($token, 'secret');
208 }
209
210 /**
211 * Test formatLink() with a link using all useful fields.
212 */
213 public function testFormatLinkComplete()
214 {
215 $indexUrl = 'https://domain.tld/sub/';
216 $link = [
217 'id' => 12,
218 'url' => 'http://lol.lol',
219 'shorturl' => 'abc',
220 'title' => 'Important Title',
221 'description' => 'It is very lol<tag>' . PHP_EOL . 'new line',
222 'tags' => 'blip .blop ',
223 'private' => '1',
224 'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'),
225 'updated' => \DateTime::createFromFormat('Ymd_His', '20170107_160612'),
226 ];
227
228 $expected = [
229 'id' => 12,
230 'url' => 'http://lol.lol',
231 'shorturl' => 'abc',
232 'title' => 'Important Title',
233 'description' => 'It is very lol<tag>' . PHP_EOL . 'new line',
234 'tags' => ['blip', '.blop'],
235 'private' => true,
236 'created' => '2017-01-07T16:01:02+00:00',
237 'updated' => '2017-01-07T16:06:12+00:00',
238 ];
239
240 $this->assertEquals($expected, ApiUtils::formatLink($link, $indexUrl));
241 }
242
243 /**
244 * Test formatLink() with only minimal fields filled, and internal link.
245 */
246 public function testFormatLinkMinimalNote()
247 {
248 $indexUrl = 'https://domain.tld/sub/';
249 $link = [
250 'id' => 12,
251 'url' => '?abc',
252 'shorturl' => 'abc',
253 'title' => 'Note',
254 'description' => '',
255 'tags' => '',
256 'private' => '',
257 'created' => \DateTime::createFromFormat('Ymd_His', '20170107_160102'),
258 ];
259
260 $expected = [
261 'id' => 12,
262 'url' => 'https://domain.tld/sub/?abc',
263 'shorturl' => 'abc',
264 'title' => 'Note',
265 'description' => '',
266 'tags' => [],
267 'private' => false,
268 'created' => '2017-01-07T16:01:02+00:00',
269 'updated' => '',
270 ];
271
272 $this->assertEquals($expected, ApiUtils::formatLink($link, $indexUrl));
273 }
274
275 /**
276 * Test updateLink with valid data, and also unnecessary fields.
277 */
278 public function testUpdateLink()
279 {
280 $created = \DateTime::createFromFormat('Ymd_His', '20170107_160102');
281 $old = [
282 'id' => 12,
283 'url' => '?abc',
284 'shorturl' => 'abc',
285 'title' => 'Note',
286 'description' => '',
287 'tags' => '',
288 'private' => '',
289 'created' => $created,
290 ];
291
292 $new = [
293 'id' => 13,
294 'shorturl' => 'nope',
295 'url' => 'http://somewhere.else',
296 'title' => 'Le Cid',
297 'description' => 'Percé jusques au fond du cœur [...]',
298 'tags' => 'corneille rodrigue',
299 'private' => true,
300 'created' => 'creation',
301 'updated' => 'updation',
302 ];
303
304 $result = ApiUtils::updateLink($old, $new);
305 $this->assertEquals(12, $result['id']);
306 $this->assertEquals('http://somewhere.else', $result['url']);
307 $this->assertEquals('abc', $result['shorturl']);
308 $this->assertEquals('Le Cid', $result['title']);
309 $this->assertEquals('Percé jusques au fond du cœur [...]', $result['description']);
310 $this->assertEquals('corneille rodrigue', $result['tags']);
311 $this->assertEquals(true, $result['private']);
312 $this->assertEquals($created, $result['created']);
313 $this->assertTrue(new \DateTime('5 seconds ago') < $result['updated']);
314 }
315
316 /**
317 * Test updateLink with minimal data.
318 */
319 public function testUpdateLinkMinimal()
320 {
321 $created = \DateTime::createFromFormat('Ymd_His', '20170107_160102');
322 $old = [
323 'id' => 12,
324 'url' => '?abc',
325 'shorturl' => 'abc',
326 'title' => 'Note',
327 'description' => 'Interesting description!',
328 'tags' => 'doggo',
329 'private' => true,
330 'created' => $created,
331 ];
332
333 $new = [
334 'url' => '',
335 'title' => '',
336 'description' => '',
337 'tags' => '',
338 'private' => false,
339 ];
340
341 $result = ApiUtils::updateLink($old, $new);
342 $this->assertEquals(12, $result['id']);
343 $this->assertEquals('?abc', $result['url']);
344 $this->assertEquals('abc', $result['shorturl']);
345 $this->assertEquals('?abc', $result['title']);
346 $this->assertEquals('', $result['description']);
347 $this->assertEquals('', $result['tags']);
348 $this->assertEquals(false, $result['private']);
349 $this->assertEquals($created, $result['created']);
350 $this->assertTrue(new \DateTime('5 seconds ago') < $result['updated']);
351 }
352}
diff --git a/tests/api/controllers/DeleteLinkTest.php b/tests/api/controllers/DeleteLinkTest.php
new file mode 100644
index 00000000..7d797137
--- /dev/null
+++ b/tests/api/controllers/DeleteLinkTest.php
@@ -0,0 +1,126 @@
1<?php
2
3
4namespace Shaarli\Api\Controllers;
5
6use Shaarli\Config\ConfigManager;
7use Slim\Container;
8use Slim\Http\Environment;
9use Slim\Http\Request;
10use Slim\Http\Response;
11
12class DeleteLinkTest extends \PHPUnit_Framework_TestCase
13{
14 /**
15 * @var string datastore to test write operations
16 */
17 protected static $testDatastore = 'sandbox/datastore.php';
18
19 /**
20 * @var string datastore to test write operations
21 */
22 protected static $testHistory = 'sandbox/history.php';
23
24 /**
25 * @var ConfigManager instance
26 */
27 protected $conf;
28
29 /**
30 * @var \ReferenceLinkDB instance.
31 */
32 protected $refDB = null;
33
34 /**
35 * @var \LinkDB instance.
36 */
37 protected $linkDB;
38
39 /**
40 * @var \History instance.
41 */
42 protected $history;
43
44 /**
45 * @var Container instance.
46 */
47 protected $container;
48
49 /**
50 * @var Links controller instance.
51 */
52 protected $controller;
53
54 /**
55 * Before each test, instantiate a new Api with its config, plugins and links.
56 */
57 public function setUp()
58 {
59 $this->conf = new ConfigManager('tests/utils/config/configJson');
60 $this->refDB = new \ReferenceLinkDB();
61 $this->refDB->write(self::$testDatastore);
62 $this->linkDB = new \LinkDB(self::$testDatastore, true, false);
63 $refHistory = new \ReferenceHistory();
64 $refHistory->write(self::$testHistory);
65 $this->history = new \History(self::$testHistory);
66 $this->container = new Container();
67 $this->container['conf'] = $this->conf;
68 $this->container['db'] = $this->linkDB;
69 $this->container['history'] = $this->history;
70
71 $this->controller = new Links($this->container);
72 }
73
74 /**
75 * After each test, remove the test datastore.
76 */
77 public function tearDown()
78 {
79 @unlink(self::$testDatastore);
80 @unlink(self::$testHistory);
81 }
82
83 /**
84 * Test DELETE link endpoint: the link should be removed.
85 */
86 public function testDeleteLinkValid()
87 {
88 $id = '41';
89 $this->assertTrue(isset($this->linkDB[$id]));
90 $env = Environment::mock([
91 'REQUEST_METHOD' => 'DELETE',
92 ]);
93 $request = Request::createFromEnvironment($env);
94
95 $response = $this->controller->deleteLink($request, new Response(), ['id' => $id]);
96 $this->assertEquals(204, $response->getStatusCode());
97 $this->assertEmpty((string) $response->getBody());
98
99 $this->linkDB = new \LinkDB(self::$testDatastore, true, false);
100 $this->assertFalse(isset($this->linkDB[$id]));
101
102 $historyEntry = $this->history->getHistory()[0];
103 $this->assertEquals(\History::DELETED, $historyEntry['event']);
104 $this->assertTrue(
105 (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
106 );
107 $this->assertEquals($id, $historyEntry['id']);
108 }
109
110 /**
111 * Test DELETE link endpoint: reach not existing ID.
112 *
113 * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
114 */
115 public function testDeleteLink404()
116 {
117 $id = -1;
118 $this->assertFalse(isset($this->linkDB[$id]));
119 $env = Environment::mock([
120 'REQUEST_METHOD' => 'DELETE',
121 ]);
122 $request = Request::createFromEnvironment($env);
123
124 $this->controller->deleteLink($request, new Response(), ['id' => $id]);
125 }
126}
diff --git a/tests/api/controllers/GetLinkIdTest.php b/tests/api/controllers/GetLinkIdTest.php
new file mode 100644
index 00000000..57528d5a
--- /dev/null
+++ b/tests/api/controllers/GetLinkIdTest.php
@@ -0,0 +1,132 @@
1<?php
2
3namespace Shaarli\Api\Controllers;
4
5use Shaarli\Config\ConfigManager;
6
7use Slim\Container;
8use Slim\Http\Environment;
9use Slim\Http\Request;
10use Slim\Http\Response;
11
12/**
13 * Class GetLinkIdTest
14 *
15 * Test getLink by ID API service.
16 *
17 * @see http://shaarli.github.io/api-documentation/#links-link-get
18 *
19 * @package Shaarli\Api\Controllers
20 */
21class GetLinkIdTest extends \PHPUnit_Framework_TestCase
22{
23 /**
24 * @var string datastore to test write operations
25 */
26 protected static $testDatastore = 'sandbox/datastore.php';
27
28 /**
29 * @var ConfigManager instance
30 */
31 protected $conf;
32
33 /**
34 * @var \ReferenceLinkDB instance.
35 */
36 protected $refDB = null;
37
38 /**
39 * @var Container instance.
40 */
41 protected $container;
42
43 /**
44 * @var Links controller instance.
45 */
46 protected $controller;
47
48 /**
49 * Number of JSON fields per link.
50 */
51 const NB_FIELDS_LINK = 9;
52
53 /**
54 * Before each test, instantiate a new Api with its config, plugins and links.
55 */
56 public function setUp()
57 {
58 $this->conf = new ConfigManager('tests/utils/config/configJson');
59 $this->refDB = new \ReferenceLinkDB();
60 $this->refDB->write(self::$testDatastore);
61
62 $this->container = new Container();
63 $this->container['conf'] = $this->conf;
64 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
65 $this->container['history'] = null;
66
67 $this->controller = new Links($this->container);
68 }
69
70 /**
71 * After each test, remove the test datastore.
72 */
73 public function tearDown()
74 {
75 @unlink(self::$testDatastore);
76 }
77
78 /**
79 * Test basic getLink service: return link ID=41.
80 */
81 public function testGetLinkId()
82 {
83 // Used by index_url().
84 $_SERVER['SERVER_NAME'] = 'domain.tld';
85 $_SERVER['SERVER_PORT'] = 80;
86 $_SERVER['SCRIPT_NAME'] = '/';
87
88 $id = 41;
89 $env = Environment::mock([
90 'REQUEST_METHOD' => 'GET',
91 ]);
92 $request = Request::createFromEnvironment($env);
93
94 $response = $this->controller->getLink($request, new Response(), ['id' => $id]);
95 $this->assertEquals(200, $response->getStatusCode());
96 $data = json_decode((string) $response->getBody(), true);
97 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
98 $this->assertEquals($id, $data['id']);
99
100 // Check link elements
101 $this->assertEquals('http://domain.tld/?WDWyig', $data['url']);
102 $this->assertEquals('WDWyig', $data['shorturl']);
103 $this->assertEquals('Link title: @website', $data['title']);
104 $this->assertEquals(
105 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
106 $data['description']
107 );
108 $this->assertEquals('sTuff', $data['tags'][0]);
109 $this->assertEquals(false, $data['private']);
110 $this->assertEquals(
111 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM),
112 $data['created']
113 );
114 $this->assertEmpty($data['updated']);
115 }
116
117 /**
118 * Test basic getLink service: get non existent link => ApiLinkNotFoundException.
119 *
120 * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
121 * @expectedExceptionMessage Link not found
122 */
123 public function testGetLink404()
124 {
125 $env = Environment::mock([
126 'REQUEST_METHOD' => 'GET',
127 ]);
128 $request = Request::createFromEnvironment($env);
129
130 $this->controller->getLink($request, new Response(), ['id' => -1]);
131 }
132}
diff --git a/tests/api/controllers/GetLinksTest.php b/tests/api/controllers/GetLinksTest.php
new file mode 100644
index 00000000..d22ed3bf
--- /dev/null
+++ b/tests/api/controllers/GetLinksTest.php
@@ -0,0 +1,472 @@
1<?php
2namespace Shaarli\Api\Controllers;
3
4use Shaarli\Config\ConfigManager;
5
6use Slim\Container;
7use Slim\Http\Environment;
8use Slim\Http\Request;
9use Slim\Http\Response;
10
11/**
12 * Class GetLinksTest
13 *
14 * Test get Link list REST API service.
15 *
16 * @see http://shaarli.github.io/api-documentation/#links-links-collection-get
17 *
18 * @package Shaarli\Api\Controllers
19 */
20class GetLinksTest extends \PHPUnit_Framework_TestCase
21{
22 /**
23 * @var string datastore to test write operations
24 */
25 protected static $testDatastore = 'sandbox/datastore.php';
26
27 /**
28 * @var ConfigManager instance
29 */
30 protected $conf;
31
32 /**
33 * @var \ReferenceLinkDB instance.
34 */
35 protected $refDB = null;
36
37 /**
38 * @var Container instance.
39 */
40 protected $container;
41
42 /**
43 * @var Links controller instance.
44 */
45 protected $controller;
46
47 /**
48 * Number of JSON field per link.
49 */
50 const NB_FIELDS_LINK = 9;
51
52 /**
53 * Before every test, instantiate a new Api with its config, plugins and links.
54 */
55 public function setUp()
56 {
57 $this->conf = new ConfigManager('tests/utils/config/configJson');
58 $this->refDB = new \ReferenceLinkDB();
59 $this->refDB->write(self::$testDatastore);
60
61 $this->container = new Container();
62 $this->container['conf'] = $this->conf;
63 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
64 $this->container['history'] = null;
65
66 $this->controller = new Links($this->container);
67 }
68
69 /**
70 * After every test, remove the test datastore.
71 */
72 public function tearDown()
73 {
74 @unlink(self::$testDatastore);
75 }
76
77 /**
78 * Test basic getLinks service: returns all links.
79 */
80 public function testGetLinks()
81 {
82 // Used by index_url().
83 $_SERVER['SERVER_NAME'] = 'domain.tld';
84 $_SERVER['SERVER_PORT'] = 80;
85 $_SERVER['SCRIPT_NAME'] = '/';
86
87 $env = Environment::mock([
88 'REQUEST_METHOD' => 'GET',
89 ]);
90 $request = Request::createFromEnvironment($env);
91
92 $response = $this->controller->getLinks($request, new Response());
93 $this->assertEquals(200, $response->getStatusCode());
94 $data = json_decode((string) $response->getBody(), true);
95 $this->assertEquals($this->refDB->countLinks(), count($data));
96
97 // Check order
98 $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
99 $cpt = 0;
100 foreach ($data as $link) {
101 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
102 $this->assertEquals($order[$cpt++], $link['id']);
103 }
104
105 // Check first element fields
106 $first = $data[0];
107 $this->assertEquals('http://domain.tld/?WDWyig', $first['url']);
108 $this->assertEquals('WDWyig', $first['shorturl']);
109 $this->assertEquals('Link title: @website', $first['title']);
110 $this->assertEquals(
111 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag',
112 $first['description']
113 );
114 $this->assertEquals('sTuff', $first['tags'][0]);
115 $this->assertEquals(false, $first['private']);
116 $this->assertEquals(
117 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM),
118 $first['created']
119 );
120 $this->assertEmpty($first['updated']);
121
122 // Multi tags
123 $link = $data[1];
124 $this->assertEquals(7, count($link['tags']));
125
126 // Update date
127 $this->assertEquals(
128 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM),
129 $link['updated']
130 );
131 }
132
133 /**
134 * Test getLinks service with offset and limit parameter:
135 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
136 */
137 public function testGetLinksOffsetLimit()
138 {
139 $env = Environment::mock([
140 'REQUEST_METHOD' => 'GET',
141 'QUERY_STRING' => 'offset=1&limit=1'
142 ]);
143 $request = Request::createFromEnvironment($env);
144 $response = $this->controller->getLinks($request, new Response());
145 $this->assertEquals(200, $response->getStatusCode());
146 $data = json_decode((string) $response->getBody(), true);
147 $this->assertEquals(1, count($data));
148 $this->assertEquals(8, $data[0]['id']);
149 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
150 }
151
152 /**
153 * Test getLinks with limit=all (return all link).
154 */
155 public function testGetLinksLimitAll()
156 {
157 $env = Environment::mock([
158 'REQUEST_METHOD' => 'GET',
159 'QUERY_STRING' => 'limit=all'
160 ]);
161 $request = Request::createFromEnvironment($env);
162 $response = $this->controller->getLinks($request, new Response());
163 $this->assertEquals(200, $response->getStatusCode());
164 $data = json_decode((string) $response->getBody(), true);
165 $this->assertEquals($this->refDB->countLinks(), count($data));
166 // Check order
167 $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
168 $cpt = 0;
169 foreach ($data as $link) {
170 $this->assertEquals(self::NB_FIELDS_LINK, count($link));
171 $this->assertEquals($order[$cpt++], $link['id']);
172 }
173 }
174
175 /**
176 * Test getLinks service with offset and limit parameter:
177 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
178 */
179 public function testGetLinksOffsetTooHigh()
180 {
181 $env = Environment::mock([
182 'REQUEST_METHOD' => 'GET',
183 'QUERY_STRING' => 'offset=100'
184 ]);
185 $request = Request::createFromEnvironment($env);
186 $response = $this->controller->getLinks($request, new Response());
187 $this->assertEquals(200, $response->getStatusCode());
188 $data = json_decode((string) $response->getBody(), true);
189 $this->assertEmpty(count($data));
190 }
191
192 /**
193 * Test getLinks with visibility parameter set to all
194 */
195 public function testGetLinksVisibilityAll()
196 {
197 $env = Environment::mock(
198 [
199 'REQUEST_METHOD' => 'GET',
200 'QUERY_STRING' => 'visibility=all'
201 ]
202 );
203 $request = Request::createFromEnvironment($env);
204 $response = $this->controller->getLinks($request, new Response());
205 $this->assertEquals(200, $response->getStatusCode());
206 $data = json_decode((string)$response->getBody(), true);
207 $this->assertEquals($this->refDB->countLinks(), count($data));
208 $this->assertEquals(41, $data[0]['id']);
209 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
210 }
211
212 /**
213 * Test getLinks with visibility parameter set to private
214 */
215 public function testGetLinksVisibilityPrivate()
216 {
217 $env = Environment::mock([
218 'REQUEST_METHOD' => 'GET',
219 'QUERY_STRING' => 'visibility=private'
220 ]);
221 $request = Request::createFromEnvironment($env);
222 $response = $this->controller->getLinks($request, new Response());
223 $this->assertEquals(200, $response->getStatusCode());
224 $data = json_decode((string) $response->getBody(), true);
225 $this->assertEquals($this->refDB->countPrivateLinks(), count($data));
226 $this->assertEquals(6, $data[0]['id']);
227 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
228 }
229
230 /**
231 * Test getLinks with visibility parameter set to public
232 */
233 public function testGetLinksVisibilityPublic()
234 {
235 $env = Environment::mock(
236 [
237 'REQUEST_METHOD' => 'GET',
238 'QUERY_STRING' => 'visibility=public'
239 ]
240 );
241 $request = Request::createFromEnvironment($env);
242 $response = $this->controller->getLinks($request, new Response());
243 $this->assertEquals(200, $response->getStatusCode());
244 $data = json_decode((string)$response->getBody(), true);
245 $this->assertEquals($this->refDB->countPublicLinks(), count($data));
246 $this->assertEquals(41, $data[0]['id']);
247 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
248 }
249
250 /**
251 * Test getLinks service with offset and limit parameter:
252 * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC).
253 */
254 public function testGetLinksSearchTerm()
255 {
256 // Only in description - 1 result
257 $env = Environment::mock([
258 'REQUEST_METHOD' => 'GET',
259 'QUERY_STRING' => 'searchterm=Tropical'
260 ]);
261 $request = Request::createFromEnvironment($env);
262 $response = $this->controller->getLinks($request, new Response());
263 $this->assertEquals(200, $response->getStatusCode());
264 $data = json_decode((string) $response->getBody(), true);
265 $this->assertEquals(1, count($data));
266 $this->assertEquals(1, $data[0]['id']);
267 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
268
269 // Only in tags - 1 result
270 $env = Environment::mock([
271 'REQUEST_METHOD' => 'GET',
272 'QUERY_STRING' => 'searchterm=tag3'
273 ]);
274 $request = Request::createFromEnvironment($env);
275 $response = $this->controller->getLinks($request, new Response());
276 $this->assertEquals(200, $response->getStatusCode());
277 $data = json_decode((string) $response->getBody(), true);
278 $this->assertEquals(1, count($data));
279 $this->assertEquals(0, $data[0]['id']);
280 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
281
282 // Multiple results (2)
283 $env = Environment::mock([
284 'REQUEST_METHOD' => 'GET',
285 'QUERY_STRING' => 'searchterm=stallman'
286 ]);
287 $request = Request::createFromEnvironment($env);
288 $response = $this->controller->getLinks($request, new Response());
289 $this->assertEquals(200, $response->getStatusCode());
290 $data = json_decode((string) $response->getBody(), true);
291 $this->assertEquals(2, count($data));
292 $this->assertEquals(41, $data[0]['id']);
293 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
294 $this->assertEquals(8, $data[1]['id']);
295 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
296
297 // Multiword - 2 results
298 $env = Environment::mock([
299 'REQUEST_METHOD' => 'GET',
300 'QUERY_STRING' => 'searchterm=stallman+software'
301 ]);
302 $request = Request::createFromEnvironment($env);
303 $response = $this->controller->getLinks($request, new Response());
304 $this->assertEquals(200, $response->getStatusCode());
305 $data = json_decode((string) $response->getBody(), true);
306 $this->assertEquals(2, count($data));
307 $this->assertEquals(41, $data[0]['id']);
308 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
309 $this->assertEquals(8, $data[1]['id']);
310 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
311
312 // URL encoding
313 $env = Environment::mock([
314 'REQUEST_METHOD' => 'GET',
315 'QUERY_STRING' => 'searchterm='. urlencode('@web')
316 ]);
317 $request = Request::createFromEnvironment($env);
318 $response = $this->controller->getLinks($request, new Response());
319 $this->assertEquals(200, $response->getStatusCode());
320 $data = json_decode((string) $response->getBody(), true);
321 $this->assertEquals(2, count($data));
322 $this->assertEquals(41, $data[0]['id']);
323 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
324 $this->assertEquals(8, $data[1]['id']);
325 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
326 }
327
328 public function testGetLinksSearchTermNoResult()
329 {
330 $env = Environment::mock([
331 'REQUEST_METHOD' => 'GET',
332 'QUERY_STRING' => 'searchterm=nope'
333 ]);
334 $request = Request::createFromEnvironment($env);
335 $response = $this->controller->getLinks($request, new Response());
336 $this->assertEquals(200, $response->getStatusCode());
337 $data = json_decode((string) $response->getBody(), true);
338 $this->assertEquals(0, count($data));
339 }
340
341 public function testGetLinksSearchTags()
342 {
343 // Single tag
344 $env = Environment::mock([
345 'REQUEST_METHOD' => 'GET',
346 'QUERY_STRING' => 'searchtags=dev',
347 ]);
348 $request = Request::createFromEnvironment($env);
349 $response = $this->controller->getLinks($request, new Response());
350 $this->assertEquals(200, $response->getStatusCode());
351 $data = json_decode((string) $response->getBody(), true);
352 $this->assertEquals(2, count($data));
353 $this->assertEquals(0, $data[0]['id']);
354 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
355 $this->assertEquals(4, $data[1]['id']);
356 $this->assertEquals(self::NB_FIELDS_LINK, count($data[1]));
357
358 // Multitag + exclude
359 $env = Environment::mock([
360 'REQUEST_METHOD' => 'GET',
361 'QUERY_STRING' => 'searchtags=stuff+-gnu',
362 ]);
363 $request = Request::createFromEnvironment($env);
364 $response = $this->controller->getLinks($request, new Response());
365 $this->assertEquals(200, $response->getStatusCode());
366 $data = json_decode((string) $response->getBody(), true);
367 $this->assertEquals(1, count($data));
368 $this->assertEquals(41, $data[0]['id']);
369 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
370
371 // wildcard: placeholder at the start
372 $env = Environment::mock([
373 'REQUEST_METHOD' => 'GET',
374 'QUERY_STRING' => 'searchtags=*Tuff',
375 ]);
376 $request = Request::createFromEnvironment($env);
377 $response = $this->controller->getLinks($request, new Response());
378 $this->assertEquals(200, $response->getStatusCode());
379 $data = json_decode((string) $response->getBody(), true);
380 $this->assertEquals(2, count($data));
381 $this->assertEquals(41, $data[0]['id']);
382
383 // wildcard: placeholder at the end
384 $env = Environment::mock([
385 'REQUEST_METHOD' => 'GET',
386 'QUERY_STRING' => 'searchtags=c*',
387 ]);
388 $request = Request::createFromEnvironment($env);
389 $response = $this->controller->getLinks($request, new Response());
390 $this->assertEquals(200, $response->getStatusCode());
391 $data = json_decode((string) $response->getBody(), true);
392 $this->assertEquals(4, count($data));
393 $this->assertEquals(6, $data[0]['id']);
394
395 // wildcard: placeholder at the middle
396 $env = Environment::mock([
397 'REQUEST_METHOD' => 'GET',
398 'QUERY_STRING' => 'searchtags=w*b',
399 ]);
400 $request = Request::createFromEnvironment($env);
401 $response = $this->controller->getLinks($request, new Response());
402 $this->assertEquals(200, $response->getStatusCode());
403 $data = json_decode((string) $response->getBody(), true);
404 $this->assertEquals(4, count($data));
405 $this->assertEquals(6, $data[0]['id']);
406
407 // wildcard: match all
408 $env = Environment::mock([
409 'REQUEST_METHOD' => 'GET',
410 'QUERY_STRING' => 'searchtags=*',
411 ]);
412 $request = Request::createFromEnvironment($env);
413 $response = $this->controller->getLinks($request, new Response());
414 $this->assertEquals(200, $response->getStatusCode());
415 $data = json_decode((string) $response->getBody(), true);
416 $this->assertEquals(9, count($data));
417 $this->assertEquals(41, $data[0]['id']);
418
419 // wildcard: optional ('*' does not need to expand)
420 $env = Environment::mock([
421 'REQUEST_METHOD' => 'GET',
422 'QUERY_STRING' => 'searchtags=*stuff*',
423 ]);
424 $request = Request::createFromEnvironment($env);
425 $response = $this->controller->getLinks($request, new Response());
426 $this->assertEquals(200, $response->getStatusCode());
427 $data = json_decode((string) $response->getBody(), true);
428 $this->assertEquals(2, count($data));
429 $this->assertEquals(41, $data[0]['id']);
430
431 // wildcard: exclusions
432 $env = Environment::mock([
433 'REQUEST_METHOD' => 'GET',
434 'QUERY_STRING' => 'searchtags=*a*+-*e*',
435 ]);
436 $request = Request::createFromEnvironment($env);
437 $response = $this->controller->getLinks($request, new Response());
438 $this->assertEquals(200, $response->getStatusCode());
439 $data = json_decode((string) $response->getBody(), true);
440 $this->assertEquals(1, count($data));
441 $this->assertEquals(41, $data[0]['id']); // finds '#hashtag' in descr.
442
443 // wildcard: exclude all
444 $env = Environment::mock([
445 'REQUEST_METHOD' => 'GET',
446 'QUERY_STRING' => 'searchtags=-*',
447 ]);
448 $request = Request::createFromEnvironment($env);
449 $response = $this->controller->getLinks($request, new Response());
450 $this->assertEquals(200, $response->getStatusCode());
451 $data = json_decode((string) $response->getBody(), true);
452 $this->assertEquals(0, count($data));
453 }
454
455 /**
456 * Test getLinks service with search tags+terms.
457 */
458 public function testGetLinksSearchTermsAndTags()
459 {
460 $env = Environment::mock([
461 'REQUEST_METHOD' => 'GET',
462 'QUERY_STRING' => 'searchterm=poke&searchtags=dev',
463 ]);
464 $request = Request::createFromEnvironment($env);
465 $response = $this->controller->getLinks($request, new Response());
466 $this->assertEquals(200, $response->getStatusCode());
467 $data = json_decode((string) $response->getBody(), true);
468 $this->assertEquals(1, count($data));
469 $this->assertEquals(0, $data[0]['id']);
470 $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
471 }
472}
diff --git a/tests/api/controllers/HistoryTest.php b/tests/api/controllers/HistoryTest.php
new file mode 100644
index 00000000..61046d97
--- /dev/null
+++ b/tests/api/controllers/HistoryTest.php
@@ -0,0 +1,216 @@
1<?php
2
3
4namespace Shaarli\Api\Controllers;
5
6
7use Shaarli\Config\ConfigManager;
8use Slim\Container;
9use Slim\Http\Environment;
10use Slim\Http\Request;
11use Slim\Http\Response;
12
13require_once 'tests/utils/ReferenceHistory.php';
14
15class HistoryTest extends \PHPUnit_Framework_TestCase
16{
17 /**
18 * @var string datastore to test write operations
19 */
20 protected static $testHistory = 'sandbox/history.php';
21
22 /**
23 * @var ConfigManager instance
24 */
25 protected $conf;
26
27 /**
28 * @var \ReferenceHistory instance.
29 */
30 protected $refHistory = null;
31
32 /**
33 * @var Container instance.
34 */
35 protected $container;
36
37 /**
38 * @var History controller instance.
39 */
40 protected $controller;
41
42 /**
43 * Before every test, instantiate a new Api with its config, plugins and links.
44 */
45 public function setUp()
46 {
47 $this->conf = new ConfigManager('tests/utils/config/configJson.json.php');
48 $this->refHistory = new \ReferenceHistory();
49 $this->refHistory->write(self::$testHistory);
50 $this->container = new Container();
51 $this->container['conf'] = $this->conf;
52 $this->container['db'] = true;
53 $this->container['history'] = new \History(self::$testHistory);
54
55 $this->controller = new History($this->container);
56 }
57
58 /**
59 * After every test, remove the test datastore.
60 */
61 public function tearDown()
62 {
63 @unlink(self::$testHistory);
64 }
65
66 /**
67 * Test /history service without parameter.
68 */
69 public function testGetHistory()
70 {
71 $env = Environment::mock([
72 'REQUEST_METHOD' => 'GET',
73 ]);
74 $request = Request::createFromEnvironment($env);
75
76 $response = $this->controller->getHistory($request, new Response());
77 $this->assertEquals(200, $response->getStatusCode());
78 $data = json_decode((string) $response->getBody(), true);
79
80 $this->assertEquals($this->refHistory->count(), count($data));
81
82 $this->assertEquals(\History::DELETED, $data[0]['event']);
83 $this->assertEquals(
84 \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM),
85 $data[0]['datetime']
86 );
87 $this->assertEquals(124, $data[0]['id']);
88
89 $this->assertEquals(\History::SETTINGS, $data[1]['event']);
90 $this->assertEquals(
91 \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM),
92 $data[1]['datetime']
93 );
94 $this->assertNull($data[1]['id']);
95
96 $this->assertEquals(\History::UPDATED, $data[2]['event']);
97 $this->assertEquals(
98 \DateTime::createFromFormat('Ymd_His', '20170301_121214')->format(\DateTime::ATOM),
99 $data[2]['datetime']
100 );
101 $this->assertEquals(123, $data[2]['id']);
102
103 $this->assertEquals(\History::CREATED, $data[3]['event']);
104 $this->assertEquals(
105 \DateTime::createFromFormat('Ymd_His', '20170201_121214')->format(\DateTime::ATOM),
106 $data[3]['datetime']
107 );
108 $this->assertEquals(124, $data[3]['id']);
109
110 $this->assertEquals(\History::CREATED, $data[4]['event']);
111 $this->assertEquals(
112 \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM),
113 $data[4]['datetime']
114 );
115 $this->assertEquals(123, $data[4]['id']);
116 }
117
118 /**
119 * Test /history service with limit parameter.
120 */
121 public function testGetHistoryLimit()
122 {
123 $env = Environment::mock([
124 'REQUEST_METHOD' => 'GET',
125 'QUERY_STRING' => 'limit=1'
126 ]);
127 $request = Request::createFromEnvironment($env);
128
129 $response = $this->controller->getHistory($request, new Response());
130 $this->assertEquals(200, $response->getStatusCode());
131 $data = json_decode((string) $response->getBody(), true);
132
133 $this->assertEquals(1, count($data));
134
135 $this->assertEquals(\History::DELETED, $data[0]['event']);
136 $this->assertEquals(
137 \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM),
138 $data[0]['datetime']
139 );
140 $this->assertEquals(124, $data[0]['id']);
141 }
142
143 /**
144 * Test /history service with offset parameter.
145 */
146 public function testGetHistoryOffset()
147 {
148 $env = Environment::mock([
149 'REQUEST_METHOD' => 'GET',
150 'QUERY_STRING' => 'offset=4'
151 ]);
152 $request = Request::createFromEnvironment($env);
153
154 $response = $this->controller->getHistory($request, new Response());
155 $this->assertEquals(200, $response->getStatusCode());
156 $data = json_decode((string) $response->getBody(), true);
157
158 $this->assertEquals(1, count($data));
159
160 $this->assertEquals(\History::CREATED, $data[0]['event']);
161 $this->assertEquals(
162 \DateTime::createFromFormat('Ymd_His', '20170101_121212')->format(\DateTime::ATOM),
163 $data[0]['datetime']
164 );
165 $this->assertEquals(123, $data[0]['id']);
166 }
167
168 /**
169 * Test /history service with since parameter.
170 */
171 public function testGetHistorySince()
172 {
173 $env = Environment::mock([
174 'REQUEST_METHOD' => 'GET',
175 'QUERY_STRING' => 'since=2017-03-03T00:00:00%2B00:00'
176 ]);
177 $request = Request::createFromEnvironment($env);
178
179 $response = $this->controller->getHistory($request, new Response());
180 $this->assertEquals(200, $response->getStatusCode());
181 $data = json_decode((string) $response->getBody(), true);
182
183 $this->assertEquals(1, count($data));
184
185 $this->assertEquals(\History::DELETED, $data[0]['event']);
186 $this->assertEquals(
187 \DateTime::createFromFormat('Ymd_His', '20170303_121216')->format(\DateTime::ATOM),
188 $data[0]['datetime']
189 );
190 $this->assertEquals(124, $data[0]['id']);
191 }
192
193 /**
194 * Test /history service with since parameter.
195 */
196 public function testGetHistorySinceOffsetLimit()
197 {
198 $env = Environment::mock([
199 'REQUEST_METHOD' => 'GET',
200 'QUERY_STRING' => 'since=2017-02-01T00:00:00%2B00:00&offset=1&limit=1'
201 ]);
202 $request = Request::createFromEnvironment($env);
203
204 $response = $this->controller->getHistory($request, new Response());
205 $this->assertEquals(200, $response->getStatusCode());
206 $data = json_decode((string) $response->getBody(), true);
207
208 $this->assertEquals(1, count($data));
209
210 $this->assertEquals(\History::SETTINGS, $data[0]['event']);
211 $this->assertEquals(
212 \DateTime::createFromFormat('Ymd_His', '20170302_121215')->format(\DateTime::ATOM),
213 $data[0]['datetime']
214 );
215 }
216}
diff --git a/tests/api/controllers/InfoTest.php b/tests/api/controllers/InfoTest.php
new file mode 100644
index 00000000..f7e63bfa
--- /dev/null
+++ b/tests/api/controllers/InfoTest.php
@@ -0,0 +1,115 @@
1<?php
2namespace Shaarli\Api\Controllers;
3
4use Shaarli\Config\ConfigManager;
5
6use Slim\Container;
7use Slim\Http\Environment;
8use Slim\Http\Request;
9use Slim\Http\Response;
10
11/**
12 * Class InfoTest
13 *
14 * Test REST API controller Info.
15 *
16 * @package Api\Controllers
17 */
18class InfoTest extends \PHPUnit_Framework_TestCase
19{
20 /**
21 * @var string datastore to test write operations
22 */
23 protected static $testDatastore = 'sandbox/datastore.php';
24
25 /**
26 * @var ConfigManager instance
27 */
28 protected $conf;
29
30 /**
31 * @var \ReferenceLinkDB instance.
32 */
33 protected $refDB = null;
34
35 /**
36 * @var Container instance.
37 */
38 protected $container;
39
40 /**
41 * @var Info controller instance.
42 */
43 protected $controller;
44
45 /**
46 * Before every test, instantiate a new Api with its config, plugins and links.
47 */
48 public function setUp()
49 {
50 $this->conf = new ConfigManager('tests/utils/config/configJson.json.php');
51 $this->refDB = new \ReferenceLinkDB();
52 $this->refDB->write(self::$testDatastore);
53
54 $this->container = new Container();
55 $this->container['conf'] = $this->conf;
56 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
57 $this->container['history'] = null;
58
59 $this->controller = new Info($this->container);
60 }
61
62 /**
63 * After every test, remove the test datastore.
64 */
65 public function tearDown()
66 {
67 @unlink(self::$testDatastore);
68 }
69
70 /**
71 * Test /info service.
72 */
73 public function testGetInfo()
74 {
75 $env = Environment::mock([
76 'REQUEST_METHOD' => 'GET',
77 ]);
78 $request = Request::createFromEnvironment($env);
79
80 $response = $this->controller->getInfo($request, new Response());
81 $this->assertEquals(200, $response->getStatusCode());
82 $data = json_decode((string) $response->getBody(), true);
83
84 $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
85 $this->assertEquals(2, $data['private_counter']);
86 $this->assertEquals('Shaarli', $data['settings']['title']);
87 $this->assertEquals('?', $data['settings']['header_link']);
88 $this->assertEquals('UTC', $data['settings']['timezone']);
89 $this->assertEquals(ConfigManager::$DEFAULT_PLUGINS, $data['settings']['enabled_plugins']);
90 $this->assertEquals(false, $data['settings']['default_private_links']);
91
92 $title = 'My links';
93 $headerLink = 'http://shaarli.tld';
94 $timezone = 'Europe/Paris';
95 $enabledPlugins = array('foo', 'bar');
96 $defaultPrivateLinks = true;
97 $this->conf->set('general.title', $title);
98 $this->conf->set('general.header_link', $headerLink);
99 $this->conf->set('general.timezone', $timezone);
100 $this->conf->set('general.enabled_plugins', $enabledPlugins);
101 $this->conf->set('privacy.default_private_links', $defaultPrivateLinks);
102
103 $response = $this->controller->getInfo($request, new Response());
104 $this->assertEquals(200, $response->getStatusCode());
105 $data = json_decode((string) $response->getBody(), true);
106
107 $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, $data['global_counter']);
108 $this->assertEquals(2, $data['private_counter']);
109 $this->assertEquals($title, $data['settings']['title']);
110 $this->assertEquals($headerLink, $data['settings']['header_link']);
111 $this->assertEquals($timezone, $data['settings']['timezone']);
112 $this->assertEquals($enabledPlugins, $data['settings']['enabled_plugins']);
113 $this->assertEquals($defaultPrivateLinks, $data['settings']['default_private_links']);
114 }
115}
diff --git a/tests/api/controllers/PostLinkTest.php b/tests/api/controllers/PostLinkTest.php
new file mode 100644
index 00000000..31954e39
--- /dev/null
+++ b/tests/api/controllers/PostLinkTest.php
@@ -0,0 +1,216 @@
1<?php
2
3namespace Shaarli\Api\Controllers;
4
5
6use Shaarli\Config\ConfigManager;
7use Slim\Container;
8use Slim\Http\Environment;
9use Slim\Http\Request;
10use Slim\Http\Response;
11
12/**
13 * Class PostLinkTest
14 *
15 * Test POST Link REST API service.
16 *
17 * @package Shaarli\Api\Controllers
18 */
19class PostLinkTest extends \PHPUnit_Framework_TestCase
20{
21 /**
22 * @var string datastore to test write operations
23 */
24 protected static $testDatastore = 'sandbox/datastore.php';
25
26 /**
27 * @var string datastore to test write operations
28 */
29 protected static $testHistory = 'sandbox/history.php';
30
31 /**
32 * @var ConfigManager instance
33 */
34 protected $conf;
35
36 /**
37 * @var \ReferenceLinkDB instance.
38 */
39 protected $refDB = null;
40
41 /**
42 * @var \History instance.
43 */
44 protected $history;
45
46 /**
47 * @var Container instance.
48 */
49 protected $container;
50
51 /**
52 * @var Links controller instance.
53 */
54 protected $controller;
55
56 /**
57 * Number of JSON field per link.
58 */
59 const NB_FIELDS_LINK = 9;
60
61 /**
62 * Before every test, instantiate a new Api with its config, plugins and links.
63 */
64 public function setUp()
65 {
66 $this->conf = new ConfigManager('tests/utils/config/configJson.json.php');
67 $this->refDB = new \ReferenceLinkDB();
68 $this->refDB->write(self::$testDatastore);
69
70 $refHistory = new \ReferenceHistory();
71 $refHistory->write(self::$testHistory);
72 $this->history = new \History(self::$testHistory);
73
74 $this->container = new Container();
75 $this->container['conf'] = $this->conf;
76 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
77 $this->container['history'] = new \History(self::$testHistory);
78
79 $this->controller = new Links($this->container);
80
81 $mock = $this->getMock('\Slim\Router', ['relativePathFor']);
82 $mock->expects($this->any())
83 ->method('relativePathFor')
84 ->willReturn('api/v1/links/1');
85
86 // affect @property-read... seems to work
87 $this->controller->getCi()->router = $mock;
88
89 // Used by index_url().
90 $this->controller->getCi()['environment'] = [
91 'SERVER_NAME' => 'domain.tld',
92 'SERVER_PORT' => 80,
93 'SCRIPT_NAME' => '/',
94 ];
95 }
96
97 /**
98 * After every test, remove the test datastore.
99 */
100 public function tearDown()
101 {
102 @unlink(self::$testDatastore);
103 @unlink(self::$testHistory);
104 }
105
106 /**
107 * Test link creation without any field: creates a blank note.
108 */
109 public function testPostLinkMinimal()
110 {
111 $env = Environment::mock([
112 'REQUEST_METHOD' => 'POST',
113 ]);
114
115 $request = Request::createFromEnvironment($env);
116
117 $response = $this->controller->postLink($request, new Response());
118 $this->assertEquals(201, $response->getStatusCode());
119 $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]);
120 $data = json_decode((string) $response->getBody(), true);
121 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
122 $this->assertEquals(43, $data['id']);
123 $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']);
124 $this->assertEquals('http://domain.tld/?' . $data['shorturl'], $data['url']);
125 $this->assertEquals('?' . $data['shorturl'], $data['title']);
126 $this->assertEquals('', $data['description']);
127 $this->assertEquals([], $data['tags']);
128 $this->assertEquals(false, $data['private']);
129 $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created']));
130 $this->assertEquals('', $data['updated']);
131
132 $historyEntry = $this->history->getHistory()[0];
133 $this->assertEquals(\History::CREATED, $historyEntry['event']);
134 $this->assertTrue(
135 (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
136 );
137 $this->assertEquals(43, $historyEntry['id']);
138 }
139
140 /**
141 * Test link creation with all available fields.
142 */
143 public function testPostLinkFull()
144 {
145 $link = [
146 'url' => 'website.tld/test?foo=bar',
147 'title' => 'new entry',
148 'description' => 'shaare description',
149 'tags' => ['one', 'two'],
150 'private' => true,
151 ];
152 $env = Environment::mock([
153 'REQUEST_METHOD' => 'POST',
154 'CONTENT_TYPE' => 'application/json'
155 ]);
156
157 $request = Request::createFromEnvironment($env);
158 $request = $request->withParsedBody($link);
159 $response = $this->controller->postLink($request, new Response());
160
161 $this->assertEquals(201, $response->getStatusCode());
162 $this->assertEquals('api/v1/links/1', $response->getHeader('Location')[0]);
163 $data = json_decode((string) $response->getBody(), true);
164 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
165 $this->assertEquals(43, $data['id']);
166 $this->assertRegExp('/[\w-_]{6}/', $data['shorturl']);
167 $this->assertEquals('http://' . $link['url'], $data['url']);
168 $this->assertEquals($link['title'], $data['title']);
169 $this->assertEquals($link['description'], $data['description']);
170 $this->assertEquals($link['tags'], $data['tags']);
171 $this->assertEquals(true, $data['private']);
172 $this->assertTrue(new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created']));
173 $this->assertEquals('', $data['updated']);
174 }
175
176 /**
177 * Test link creation with an existing link (duplicate URL). Should return a 409 HTTP error and the existing link.
178 */
179 public function testPostLinkDuplicate()
180 {
181 $link = [
182 'url' => 'mediagoblin.org/',
183 'title' => 'new entry',
184 'description' => 'shaare description',
185 'tags' => ['one', 'two'],
186 'private' => true,
187 ];
188 $env = Environment::mock([
189 'REQUEST_METHOD' => 'POST',
190 'CONTENT_TYPE' => 'application/json'
191 ]);
192
193 $request = Request::createFromEnvironment($env);
194 $request = $request->withParsedBody($link);
195 $response = $this->controller->postLink($request, new Response());
196
197 $this->assertEquals(409, $response->getStatusCode());
198 $data = json_decode((string) $response->getBody(), true);
199 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
200 $this->assertEquals(7, $data['id']);
201 $this->assertEquals('IuWvgA', $data['shorturl']);
202 $this->assertEquals('http://mediagoblin.org/', $data['url']);
203 $this->assertEquals('MediaGoblin', $data['title']);
204 $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']);
205 $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']);
206 $this->assertEquals(false, $data['private']);
207 $this->assertEquals(
208 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'),
209 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
210 );
211 $this->assertEquals(
212 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'),
213 \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
214 );
215 }
216}
diff --git a/tests/api/controllers/PutLinkTest.php b/tests/api/controllers/PutLinkTest.php
new file mode 100644
index 00000000..8a562571
--- /dev/null
+++ b/tests/api/controllers/PutLinkTest.php
@@ -0,0 +1,222 @@
1<?php
2
3
4namespace Shaarli\Api\Controllers;
5
6
7use Shaarli\Config\ConfigManager;
8use Slim\Container;
9use Slim\Http\Environment;
10use Slim\Http\Request;
11use Slim\Http\Response;
12
13class PutLinkTest extends \PHPUnit_Framework_TestCase
14{
15 /**
16 * @var string datastore to test write operations
17 */
18 protected static $testDatastore = 'sandbox/datastore.php';
19
20 /**
21 * @var string datastore to test write operations
22 */
23 protected static $testHistory = 'sandbox/history.php';
24
25 /**
26 * @var ConfigManager instance
27 */
28 protected $conf;
29
30 /**
31 * @var \ReferenceLinkDB instance.
32 */
33 protected $refDB = null;
34
35 /**
36 * @var \History instance.
37 */
38 protected $history;
39
40 /**
41 * @var Container instance.
42 */
43 protected $container;
44
45 /**
46 * @var Links controller instance.
47 */
48 protected $controller;
49
50 /**
51 * Number of JSON field per link.
52 */
53 const NB_FIELDS_LINK = 9;
54
55 /**
56 * Before every test, instantiate a new Api with its config, plugins and links.
57 */
58 public function setUp()
59 {
60 $this->conf = new ConfigManager('tests/utils/config/configJson.json.php');
61 $this->refDB = new \ReferenceLinkDB();
62 $this->refDB->write(self::$testDatastore);
63
64 $refHistory = new \ReferenceHistory();
65 $refHistory->write(self::$testHistory);
66 $this->history = new \History(self::$testHistory);
67
68 $this->container = new Container();
69 $this->container['conf'] = $this->conf;
70 $this->container['db'] = new \LinkDB(self::$testDatastore, true, false);
71 $this->container['history'] = new \History(self::$testHistory);
72
73 $this->controller = new Links($this->container);
74
75 // Used by index_url().
76 $this->controller->getCi()['environment'] = [
77 'SERVER_NAME' => 'domain.tld',
78 'SERVER_PORT' => 80,
79 'SCRIPT_NAME' => '/',
80 ];
81 }
82
83 /**
84 * After every test, remove the test datastore.
85 */
86 public function tearDown()
87 {
88 @unlink(self::$testDatastore);
89 @unlink(self::$testHistory);
90 }
91
92 /**
93 * Test link update without value: reset the link to default values
94 */
95 public function testPutLinkMinimal()
96 {
97 $env = Environment::mock([
98 'REQUEST_METHOD' => 'PUT',
99 ]);
100 $id = '41';
101 $request = Request::createFromEnvironment($env);
102
103 $response = $this->controller->putLink($request, new Response(), ['id' => $id]);
104 $this->assertEquals(200, $response->getStatusCode());
105 $data = json_decode((string) $response->getBody(), true);
106 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
107 $this->assertEquals($id, $data['id']);
108 $this->assertEquals('WDWyig', $data['shorturl']);
109 $this->assertEquals('http://domain.tld/?WDWyig', $data['url']);
110 $this->assertEquals('?WDWyig', $data['title']);
111 $this->assertEquals('', $data['description']);
112 $this->assertEquals([], $data['tags']);
113 $this->assertEquals(false, $data['private']);
114 $this->assertEquals(
115 \DateTime::createFromFormat('Ymd_His', '20150310_114651'),
116 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
117 );
118 $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated']));
119
120 $historyEntry = $this->history->getHistory()[0];
121 $this->assertEquals(\History::UPDATED, $historyEntry['event']);
122 $this->assertTrue(
123 (new \DateTime())->add(\DateInterval::createFromDateString('-5 seconds')) < $historyEntry['datetime']
124 );
125 $this->assertEquals($id, $historyEntry['id']);
126 }
127
128 /**
129 * Test link update with new values
130 */
131 public function testPutLinkWithValues()
132 {
133 $env = Environment::mock([
134 'REQUEST_METHOD' => 'PUT',
135 'CONTENT_TYPE' => 'application/json'
136 ]);
137 $id = 41;
138 $update = [
139 'url' => 'http://somewhere.else',
140 'title' => 'Le Cid',
141 'description' => 'Percé jusques au fond du cœur [...]',
142 'tags' => ['corneille', 'rodrigue'],
143 'private' => true,
144 ];
145 $request = Request::createFromEnvironment($env);
146 $request = $request->withParsedBody($update);
147
148 $response = $this->controller->putLink($request, new Response(), ['id' => $id]);
149 $this->assertEquals(200, $response->getStatusCode());
150 $data = json_decode((string) $response->getBody(), true);
151 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
152 $this->assertEquals($id, $data['id']);
153 $this->assertEquals('WDWyig', $data['shorturl']);
154 $this->assertEquals('http://somewhere.else', $data['url']);
155 $this->assertEquals('Le Cid', $data['title']);
156 $this->assertEquals('Percé jusques au fond du cœur [...]', $data['description']);
157 $this->assertEquals(['corneille', 'rodrigue'], $data['tags']);
158 $this->assertEquals(true, $data['private']);
159 $this->assertEquals(
160 \DateTime::createFromFormat('Ymd_His', '20150310_114651'),
161 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
162 );
163 $this->assertTrue(new \DateTime('5 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['updated']));
164 }
165
166 /**
167 * Test link update with an existing URL: 409 Conflict with the existing link as body
168 */
169 public function testPutLinkDuplicate()
170 {
171 $link = [
172 'url' => 'mediagoblin.org/',
173 'title' => 'new entry',
174 'description' => 'shaare description',
175 'tags' => ['one', 'two'],
176 'private' => true,
177 ];
178 $env = Environment::mock([
179 'REQUEST_METHOD' => 'PUT',
180 'CONTENT_TYPE' => 'application/json'
181 ]);
182
183 $request = Request::createFromEnvironment($env);
184 $request = $request->withParsedBody($link);
185 $response = $this->controller->putLink($request, new Response(), ['id' => 41]);
186
187 $this->assertEquals(409, $response->getStatusCode());
188 $data = json_decode((string) $response->getBody(), true);
189 $this->assertEquals(self::NB_FIELDS_LINK, count($data));
190 $this->assertEquals(7, $data['id']);
191 $this->assertEquals('IuWvgA', $data['shorturl']);
192 $this->assertEquals('http://mediagoblin.org/', $data['url']);
193 $this->assertEquals('MediaGoblin', $data['title']);
194 $this->assertEquals('A free software media publishing platform #hashtagOther', $data['description']);
195 $this->assertEquals(['gnu', 'media', 'web', '.hidden', 'hashtag'], $data['tags']);
196 $this->assertEquals(false, $data['private']);
197 $this->assertEquals(
198 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130614_184135'),
199 \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
200 );
201 $this->assertEquals(
202 \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20130615_184230'),
203 \DateTime::createFromFormat(\DateTime::ATOM, $data['updated'])
204 );
205 }
206
207 /**
208 * Test link update on non existent link => ApiLinkNotFoundException.
209 *
210 * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
211 * @expectedExceptionMessage Link not found
212 */
213 public function testGetLink404()
214 {
215 $env = Environment::mock([
216 'REQUEST_METHOD' => 'PUT',
217 ]);
218 $request = Request::createFromEnvironment($env);
219
220 $this->controller->putLink($request, new Response(), ['id' => -1]);
221 }
222}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 00000000..d36d73cd
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,6 @@
1<?php
2
3require_once 'vendor/autoload.php';
4
5$conf = new \Shaarli\Config\ConfigManager('tests/utils/config/configJson');
6new \Shaarli\Languages('en', $conf);
diff --git a/tests/config/ConfigJsonTest.php b/tests/config/ConfigJsonTest.php
index 07f6ab49..d237bc80 100644
--- a/tests/config/ConfigJsonTest.php
+++ b/tests/config/ConfigJsonTest.php
@@ -1,11 +1,10 @@
1<?php 1<?php
2 2namespace Shaarli\Config;
3require_once 'application/config/ConfigJson.php';
4 3
5/** 4/**
6 * Class ConfigJsonTest 5 * Class ConfigJsonTest
7 */ 6 */
8class ConfigJsonTest extends PHPUnit_Framework_TestCase 7class ConfigJsonTest extends \PHPUnit_Framework_TestCase
9{ 8{
10 /** 9 /**
11 * @var ConfigJson 10 * @var ConfigJson
@@ -40,8 +39,8 @@ class ConfigJsonTest extends PHPUnit_Framework_TestCase
40 /** 39 /**
41 * Read a non existent config file -> empty array. 40 * Read a non existent config file -> empty array.
42 * 41 *
43 * @expectedException Exception 42 * @expectedException \Exception
44 * @expectedExceptionMessage An error occurred while parsing JSON file: error code #4 43 * @expectedExceptionMessageRegExp /An error occurred while parsing JSON configuration file \([\w\/\.]+\): error code #4/
45 */ 44 */
46 public function testReadInvalidJson() 45 public function testReadInvalidJson()
47 { 46 {
@@ -112,7 +111,7 @@ class ConfigJsonTest extends PHPUnit_Framework_TestCase
112 /** 111 /**
113 * Write to invalid path. 112 * Write to invalid path.
114 * 113 *
115 * @expectedException IOException 114 * @expectedException \IOException
116 */ 115 */
117 public function testWriteInvalidArray() 116 public function testWriteInvalidArray()
118 { 117 {
@@ -123,7 +122,7 @@ class ConfigJsonTest extends PHPUnit_Framework_TestCase
123 /** 122 /**
124 * Write to invalid path. 123 * Write to invalid path.
125 * 124 *
126 * @expectedException IOException 125 * @expectedException \IOException
127 */ 126 */
128 public function testWriteInvalidBlank() 127 public function testWriteInvalidBlank()
129 { 128 {
diff --git a/tests/config/ConfigManagerTest.php b/tests/config/ConfigManagerTest.php
index 436e3d67..1ec447b2 100644
--- a/tests/config/ConfigManagerTest.php
+++ b/tests/config/ConfigManagerTest.php
@@ -1,4 +1,5 @@
1<?php 1<?php
2namespace Shaarli\Config;
2 3
3/** 4/**
4 * Unit tests for Class ConfigManagerTest 5 * Unit tests for Class ConfigManagerTest
@@ -6,7 +7,7 @@
6 * Note: it only test the manager with ConfigJson, 7 * Note: it only test the manager with ConfigJson,
7 * ConfigPhp is only a workaround to handle the transition to JSON type. 8 * ConfigPhp is only a workaround to handle the transition to JSON type.
8 */ 9 */
9class ConfigManagerTest extends PHPUnit_Framework_TestCase 10class ConfigManagerTest extends \PHPUnit_Framework_TestCase
10{ 11{
11 /** 12 /**
12 * @var ConfigManager 13 * @var ConfigManager
@@ -83,7 +84,7 @@ class ConfigManagerTest extends PHPUnit_Framework_TestCase
83 /** 84 /**
84 * Set with an empty key. 85 * Set with an empty key.
85 * 86 *
86 * @expectedException Exception 87 * @expectedException \Exception
87 * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*# 88 * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
88 */ 89 */
89 public function testSetEmptyKey() 90 public function testSetEmptyKey()
@@ -94,7 +95,7 @@ class ConfigManagerTest extends PHPUnit_Framework_TestCase
94 /** 95 /**
95 * Set with an array key. 96 * Set with an array key.
96 * 97 *
97 * @expectedException Exception 98 * @expectedException \Exception
98 * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*# 99 * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
99 */ 100 */
100 public function testSetArrayKey() 101 public function testSetArrayKey()
@@ -105,7 +106,7 @@ class ConfigManagerTest extends PHPUnit_Framework_TestCase
105 /** 106 /**
106 * Try to write the config without mandatory parameter (e.g. 'login'). 107 * Try to write the config without mandatory parameter (e.g. 'login').
107 * 108 *
108 * @expectedException MissingFieldConfigException 109 * @expectedException Shaarli\Config\Exception\MissingFieldConfigException
109 */ 110 */
110 public function testWriteMissingParameter() 111 public function testWriteMissingParameter()
111 { 112 {
diff --git a/tests/config/ConfigPhpTest.php b/tests/config/ConfigPhpTest.php
index 58cd8d2a..be23eea1 100644
--- a/tests/config/ConfigPhpTest.php
+++ b/tests/config/ConfigPhpTest.php
@@ -1,11 +1,10 @@
1<?php 1<?php
2 2namespace Shaarli\Config;
3require_once 'application/config/ConfigPhp.php';
4 3
5/** 4/**
6 * Class ConfigPhpTest 5 * Class ConfigPhpTest
7 */ 6 */
8class ConfigPhpTest extends PHPUnit_Framework_TestCase 7class ConfigPhpTest extends \PHPUnit_Framework_TestCase
9{ 8{
10 /** 9 /**
11 * @var ConfigPhp 10 * @var ConfigPhp
@@ -38,6 +37,20 @@ class ConfigPhpTest extends PHPUnit_Framework_TestCase
38 } 37 }
39 38
40 /** 39 /**
40 * Read an empty existent config file -> array with blank default values.
41 */
42 public function testReadEmpty()
43 {
44 $dataFile = 'tests/utils/config/emptyConfigPhp.php';
45 $conf = $this->configIO->read($dataFile);
46 $this->assertEmpty($conf['login']);
47 $this->assertEmpty($conf['title']);
48 $this->assertEmpty($conf['titleLink']);
49 $this->assertEmpty($conf['config']);
50 $this->assertEmpty($conf['plugins']);
51 }
52
53 /**
41 * Write a new config file. 54 * Write a new config file.
42 */ 55 */
43 public function testWriteNew() 56 public function testWriteNew()
diff --git a/tests/config/ConfigPluginTest.php b/tests/config/ConfigPluginTest.php
index 3b37cd79..deb02c9e 100644
--- a/tests/config/ConfigPluginTest.php
+++ b/tests/config/ConfigPluginTest.php
@@ -1,14 +1,14 @@
1<?php 1<?php
2/** 2namespace Shaarli\Config;
3 * Config' tests 3
4 */ 4use Shaarli\Config\Exception\PluginConfigOrderException;
5 5
6require_once 'application/config/ConfigPlugin.php'; 6require_once 'application/config/ConfigPlugin.php';
7 7
8/** 8/**
9 * Unitary tests for Shaarli config related functions 9 * Unitary tests for Shaarli config related functions
10 */ 10 */
11class ConfigPluginTest extends PHPUnit_Framework_TestCase 11class ConfigPluginTest extends \PHPUnit_Framework_TestCase
12{ 12{
13 /** 13 /**
14 * Test save_plugin_config with valid data. 14 * Test save_plugin_config with valid data.
@@ -39,7 +39,7 @@ class ConfigPluginTest extends PHPUnit_Framework_TestCase
39 /** 39 /**
40 * Test save_plugin_config with invalid data. 40 * Test save_plugin_config with invalid data.
41 * 41 *
42 * @expectedException PluginConfigOrderException 42 * @expectedException Shaarli\Config\Exception\PluginConfigOrderException
43 */ 43 */
44 public function testSavePluginConfigInvalid() 44 public function testSavePluginConfigInvalid()
45 { 45 {
diff --git a/tests/docker/alpine36/Dockerfile b/tests/docker/alpine36/Dockerfile
new file mode 100644
index 00000000..fa84f6e2
--- /dev/null
+++ b/tests/docker/alpine36/Dockerfile
@@ -0,0 +1,34 @@
1FROM alpine:3.6
2MAINTAINER Shaarli Community
3
4RUN apk --update --no-cache add \
5 ca-certificates \
6 curl \
7 make \
8 php7 \
9 php7-ctype \
10 php7-curl \
11 php7-dom \
12 php7-gd \
13 php7-iconv \
14 php7-intl \
15 php7-json \
16 php7-mbstring \
17 php7-openssl \
18 php7-phar \
19 php7-session \
20 php7-simplexml \
21 php7-tokenizer \
22 php7-xdebug \
23 php7-xml \
24 php7-zlib \
25 rsync
26
27RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
28
29RUN mkdir /shaarli
30WORKDIR /shaarli
31VOLUME /shaarli
32
33ENTRYPOINT ["make"]
34CMD []
diff --git a/tests/docker/debian8/Dockerfile b/tests/docker/debian8/Dockerfile
new file mode 100644
index 00000000..eaa34e9b
--- /dev/null
+++ b/tests/docker/debian8/Dockerfile
@@ -0,0 +1,35 @@
1FROM debian:jessie
2MAINTAINER Shaarli Community
3
4ENV TERM dumb
5ENV DEBIAN_FRONTEND noninteractive
6ENV LANG en_US.UTF-8
7ENV LANGUAGE en_US:en
8
9RUN apt-get update \
10 && apt-get install --no-install-recommends -y \
11 ca-certificates \
12 curl \
13 locales \
14 make \
15 php5 \
16 php5-curl \
17 php5-gd \
18 php5-intl \
19 php5-xdebug \
20 rsync \
21 && apt-get clean
22
23RUN locale-gen en_US.UTF-8 \
24 && locale-gen de_DE.UTF-8 \
25 && locale-gen fr_FR.UTF-8
26
27ADD https://getcomposer.org/composer.phar /usr/local/bin/composer
28RUN chmod 755 /usr/local/bin/composer
29
30RUN mkdir /shaarli
31WORKDIR /shaarli
32VOLUME /shaarli
33
34ENTRYPOINT ["make"]
35CMD []
diff --git a/tests/docker/debian9/Dockerfile b/tests/docker/debian9/Dockerfile
new file mode 100644
index 00000000..3ab4b93d
--- /dev/null
+++ b/tests/docker/debian9/Dockerfile
@@ -0,0 +1,36 @@
1FROM debian:stretch
2MAINTAINER Shaarli Community
3
4ENV TERM dumb
5ENV DEBIAN_FRONTEND noninteractive
6ENV LANG en_US.UTF-8
7ENV LANGUAGE en_US:en
8
9RUN apt-get update \
10 && apt-get install --no-install-recommends -y \
11 ca-certificates \
12 curl \
13 locales \
14 make \
15 php7.0 \
16 php7.0-curl \
17 php7.0-gd \
18 php7.0-intl \
19 php7.0-xml \
20 php-xdebug \
21 rsync \
22 && apt-get clean
23
24RUN locale-gen en_US.UTF-8 \
25 && locale-gen de_DE.UTF-8 \
26 && locale-gen fr_FR.UTF-8
27
28ADD https://getcomposer.org/composer.phar /usr/local/bin/composer
29RUN chmod 755 /usr/local/bin/composer
30
31RUN mkdir /shaarli
32WORKDIR /shaarli
33VOLUME /shaarli
34
35ENTRYPOINT ["make"]
36CMD []
diff --git a/tests/docker/ubuntu16/Dockerfile b/tests/docker/ubuntu16/Dockerfile
new file mode 100644
index 00000000..e53ed9e3
--- /dev/null
+++ b/tests/docker/ubuntu16/Dockerfile
@@ -0,0 +1,36 @@
1FROM ubuntu:16.04
2MAINTAINER Shaarli Community
3
4ENV TERM dumb
5ENV DEBIAN_FRONTEND noninteractive
6ENV LANG en_US.UTF-8
7ENV LANGUAGE en_US:en
8
9RUN apt-get update \
10 && apt-get install --no-install-recommends -y \
11 ca-certificates \
12 curl \
13 language-pack-de \
14 language-pack-en \
15 language-pack-fr \
16 locales \
17 make \
18 php7.0 \
19 php7.0-curl \
20 php7.0-gd \
21 php7.0-intl \
22 php7.0-xml \
23 php-xdebug \
24 rsync \
25 && apt-get clean
26
27ADD https://getcomposer.org/composer.phar /usr/local/bin/composer
28RUN chmod 755 /usr/local/bin/composer
29
30RUN useradd -m dev \
31 && mkdir /shaarli
32USER dev
33WORKDIR /shaarli
34
35ENTRYPOINT ["make"]
36CMD []
diff --git a/tests/languages/bootstrap.php b/tests/languages/bootstrap.php
new file mode 100644
index 00000000..da6ac2e4
--- /dev/null
+++ b/tests/languages/bootstrap.php
@@ -0,0 +1,6 @@
1<?php
2require_once 'tests/bootstrap.php';
3
4if (! empty(getenv('UT_LOCALE'))) {
5 setlocale(LC_ALL, getenv('UT_LOCALE'));
6}
diff --git a/tests/languages/de/UtilsDeTest.php b/tests/languages/de/UtilsDeTest.php
new file mode 100644
index 00000000..4569c923
--- /dev/null
+++ b/tests/languages/de/UtilsDeTest.php
@@ -0,0 +1,119 @@
1<?php
2
3require_once 'tests/UtilsTest.php';
4
5
6class UtilsDeTest extends UtilsTest
7{
8 /**
9 * Test date_format().
10 */
11 public function testDateFormat()
12 {
13 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
14 $this->assertRegExp('/1\. Januar 2017 (um )?10:11:12 GMT\+0?3(:00)?/', format_date($date, true, true));
15 }
16
17 /**
18 * Test date_format() without time.
19 */
20 public function testDateFormatNoTime()
21 {
22 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
23 $this->assertRegExp('/1\. Januar 2017/', format_date($date, false,true));
24 }
25
26 /**
27 * Test date_format() using builtin PHP function strftime.
28 */
29 public function testDateFormatDefault()
30 {
31 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
32 $this->assertEquals('So 01 Jan 2017 10:11:12 EAT', format_date($date, true, false));
33 }
34
35 /**
36 * Test date_format() using builtin PHP function strftime without time.
37 */
38 public function testDateFormatDefaultNoTime()
39 {
40 $date = DateTime::createFromFormat('Ymd_His', '20170201_101112');
41 $this->assertEquals('01.02.2017', format_date($date, false, false));
42 }
43
44 /**
45 * Test autoLocale with a simple value
46 */
47 public function testAutoLocaleValid()
48 {
49 $current = setlocale(LC_ALL, 0);
50 $header = 'en-us';
51 autoLocale($header);
52 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
53
54 setlocale(LC_ALL, $current);
55 }
56
57 /**
58 * Test autoLocale with an alternative locale value
59 */
60 public function testAutoLocaleValidAlternative()
61 {
62 $current = setlocale(LC_ALL, 0);
63 $header = 'en_us.UTF8';
64 autoLocale($header);
65 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
66
67 setlocale(LC_ALL, $current);
68 }
69
70 /**
71 * Test autoLocale with multiples value, the first one is valid
72 */
73 public function testAutoLocaleMultipleFirstValid()
74 {
75 $current = setlocale(LC_ALL, 0);
76 $header = 'en-us,de-de';
77 autoLocale($header);
78 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
79
80 setlocale(LC_ALL, $current);
81 }
82
83 /**
84 * Test autoLocale with multiples value, the second one is available
85 */
86 public function testAutoLocaleMultipleSecondAvailable()
87 {
88 $current = setlocale(LC_ALL, 0);
89 $header = 'mag_IN,fr-fr';
90 autoLocale($header);
91 $this->assertEquals('fr_FR.utf8', setlocale(LC_ALL, 0));
92
93 setlocale(LC_ALL, $current);
94 }
95
96 /**
97 * Test autoLocale without value: defaults to en_US.
98 */
99 public function testAutoLocaleBlank()
100 {
101 $current = setlocale(LC_ALL, 0);
102 autoLocale('');
103 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
104
105 setlocale(LC_ALL, $current);
106 }
107
108 /**
109 * Test autoLocale with an unavailable value: defaults to en_US.
110 */
111 public function testAutoLocaleUnavailable()
112 {
113 $current = setlocale(LC_ALL, 0);
114 autoLocale('mag_IN');
115 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
116
117 setlocale(LC_ALL, $current);
118 }
119}
diff --git a/tests/languages/en/UtilsEnTest.php b/tests/languages/en/UtilsEnTest.php
new file mode 100644
index 00000000..a74063ae
--- /dev/null
+++ b/tests/languages/en/UtilsEnTest.php
@@ -0,0 +1,119 @@
1<?php
2
3require_once 'tests/UtilsTest.php';
4
5
6class UtilsEnTest extends UtilsTest
7{
8 /**
9 * Test date_format().
10 */
11 public function testDateFormat()
12 {
13 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
14 $this->assertRegExp('/January 1, 2017 (at )?10:11:12 AM GMT\+0?3(:00)?/', format_date($date, true, true));
15 }
16
17 /**
18 * Test date_format() without time.
19 */
20 public function testDateFormatNoTime()
21 {
22 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
23 $this->assertRegExp('/January 1, 2017/', format_date($date, false, true));
24 }
25
26 /**
27 * Test date_format() using builtin PHP function strftime.
28 */
29 public function testDateFormatDefault()
30 {
31 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
32 $this->assertEquals('Sun 01 Jan 2017 10:11:12 AM EAT', format_date($date, true, false));
33 }
34
35 /**
36 * Test date_format() using builtin PHP function strftime without time.
37 */
38 public function testDateFormatDefaultNoTime()
39 {
40 $date = DateTime::createFromFormat('Ymd_His', '20170201_101112');
41 $this->assertEquals('02/01/2017', format_date($date, false, false));
42 }
43
44 /**
45 * Test autoLocale with a simple value
46 */
47 public function testAutoLocaleValid()
48 {
49 $current = setlocale(LC_ALL, 0);
50 $header = 'de-de';
51 autoLocale($header);
52 $this->assertEquals('de_DE.utf8', setlocale(LC_ALL, 0));
53
54 setlocale(LC_ALL, $current);
55 }
56
57 /**
58 * Test autoLocale with an alternative locale value
59 */
60 public function testAutoLocaleValidAlternative()
61 {
62 $current = setlocale(LC_ALL, 0);
63 $header = 'de_de.UTF8';
64 autoLocale($header);
65 $this->assertEquals('de_DE.utf8', setlocale(LC_ALL, 0));
66
67 setlocale(LC_ALL, $current);
68 }
69
70 /**
71 * Test autoLocale with multiples value, the first one is valid
72 */
73 public function testAutoLocaleMultipleFirstValid()
74 {
75 $current = setlocale(LC_ALL, 0);
76 $header = 'de-de;en-us';
77 autoLocale($header);
78 $this->assertEquals('de_DE.utf8', setlocale(LC_ALL, 0));
79
80 setlocale(LC_ALL, $current);
81 }
82
83 /**
84 * Test autoLocale with multiples value, the second one is available
85 */
86 public function testAutoLocaleMultipleSecondAvailable()
87 {
88 $current = setlocale(LC_ALL, 0);
89 $header = 'mag_IN,fr-fr';
90 autoLocale($header);
91 $this->assertEquals('fr_FR.utf8', setlocale(LC_ALL, 0));
92
93 setlocale(LC_ALL, $current);
94 }
95
96 /**
97 * Test autoLocale without value: defaults to en_US.
98 */
99 public function testAutoLocaleBlank()
100 {
101 $current = setlocale(LC_ALL, 0);
102 autoLocale('');
103 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
104
105 setlocale(LC_ALL, $current);
106 }
107
108 /**
109 * Test autoLocale with an unavailable value: defaults to en_US.
110 */
111 public function testAutoLocaleUnavailable()
112 {
113 $current = setlocale(LC_ALL, 0);
114 autoLocale('mag_IN');
115 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
116
117 setlocale(LC_ALL, $current);
118 }
119}
diff --git a/tests/languages/fr/LanguagesFrTest.php b/tests/languages/fr/LanguagesFrTest.php
new file mode 100644
index 00000000..79d05172
--- /dev/null
+++ b/tests/languages/fr/LanguagesFrTest.php
@@ -0,0 +1,175 @@
1<?php
2
3
4namespace Shaarli;
5
6
7use Shaarli\Config\ConfigManager;
8
9/**
10 * Class LanguagesFrTest
11 *
12 * Test the translation system in PHP and gettext mode with French language.
13 *
14 * @package Shaarli
15 */
16class LanguagesFrTest extends \PHPUnit_Framework_TestCase
17{
18 /**
19 * @var string Config file path (without extension).
20 */
21 protected static $configFile = 'tests/utils/config/configJson';
22
23 /**
24 * @var ConfigManager
25 */
26 protected $conf;
27
28 /**
29 * Init: force French
30 */
31 public function setUp()
32 {
33 $this->conf = new ConfigManager(self::$configFile);
34 $this->conf->set('translation.language', 'fr');
35 }
36
37 /**
38 * Reset the locale since gettext seems to mess with it, making it too long
39 */
40 public static function tearDownAfterClass()
41 {
42 if (! empty(getenv('UT_LOCALE'))) {
43 setlocale(LC_ALL, getenv('UT_LOCALE'));
44 }
45 }
46
47 /**
48 * Test t() with a simple non identified value.
49 */
50 public function testTranslateSingleNotIDGettext()
51 {
52 $this->conf->set('translation.mode', 'gettext');
53 new Languages('en', $this->conf);
54 $text = 'abcdé 564 fgK';
55 $this->assertEquals($text, t($text));
56 }
57
58 /**
59 * Test t() with a simple identified value in gettext mode.
60 */
61 public function testTranslateSingleIDGettext()
62 {
63 $this->conf->set('translation.mode', 'gettext');
64 new Languages('en', $this->conf);
65 $text = 'permalink';
66 $this->assertEquals('permalien', t($text));
67 }
68
69 /**
70 * Test t() with a non identified plural form in gettext mode.
71 */
72 public function testTranslatePluralNotIDGettext()
73 {
74 $this->conf->set('translation.mode', 'gettext');
75 new Languages('en', $this->conf);
76 $text = 'sandwich';
77 $nText = 'sandwiches';
78 // Not ID, so English fallback, and in english, plural 0
79 $this->assertEquals('sandwiches', t($text, $nText, 0));
80 $this->assertEquals('sandwich', t($text, $nText, 1));
81 $this->assertEquals('sandwiches', t($text, $nText, 2));
82 }
83
84 /**
85 * Test t() with an identified plural form in gettext mode.
86 */
87 public function testTranslatePluralIDGettext()
88 {
89 $this->conf->set('translation.mode', 'gettext');
90 new Languages('en', $this->conf);
91 $text = 'shaare';
92 $nText = 'shaares';
93 $this->assertEquals('shaare', t($text, $nText, 0));
94 $this->assertEquals('shaare', t($text, $nText, 1));
95 $this->assertEquals('shaares', t($text, $nText, 2));
96 }
97
98 /**
99 * Test t() with a simple non identified value.
100 */
101 public function testTranslateSingleNotIDPhp()
102 {
103 $this->conf->set('translation.mode', 'php');
104 new Languages('en', $this->conf);
105 $text = 'abcdé 564 fgK';
106 $this->assertEquals($text, t($text));
107 }
108
109 /**
110 * Test t() with a simple identified value in PHP mode.
111 */
112 public function testTranslateSingleIDPhp()
113 {
114 $this->conf->set('translation.mode', 'php');
115 new Languages('en', $this->conf);
116 $text = 'permalink';
117 $this->assertEquals('permalien', t($text));
118 }
119
120 /**
121 * Test t() with a non identified plural form in PHP mode.
122 */
123 public function testTranslatePluralNotIDPhp()
124 {
125 $this->conf->set('translation.mode', 'php');
126 new Languages('en', $this->conf);
127 $text = 'sandwich';
128 $nText = 'sandwiches';
129 // Not ID, so English fallback, and in english, plural 0
130 $this->assertEquals('sandwiches', t($text, $nText, 0));
131 $this->assertEquals('sandwich', t($text, $nText, 1));
132 $this->assertEquals('sandwiches', t($text, $nText, 2));
133 }
134
135 /**
136 * Test t() with an identified plural form in PHP mode.
137 */
138 public function testTranslatePluralIDPhp()
139 {
140 $this->conf->set('translation.mode', 'php');
141 new Languages('en', $this->conf);
142 $text = 'shaare';
143 $nText = 'shaares';
144 // In english, zero is followed by plural form
145 $this->assertEquals('shaare', t($text, $nText, 0));
146 $this->assertEquals('shaare', t($text, $nText, 1));
147 $this->assertEquals('shaares', t($text, $nText, 2));
148 }
149
150 /**
151 * Test t() with an extension language file in gettext mode
152 */
153 public function testTranslationExtensionGettext()
154 {
155 $this->conf->set('translation.mode', 'gettext');
156 $this->conf->set('translation.extensions.test', 'tests/utils/languages/');
157 new Languages('en', $this->conf);
158 $txt = 'car'; // ignore me poedit
159 $this->assertEquals('voiture', t($txt, $txt, 1, 'test'));
160 $this->assertEquals('Fouille', t('Search', 'Search', 1, 'test'));
161 }
162
163 /**
164 * Test t() with an extension language file in PHP mode
165 */
166 public function testTranslationExtensionPhp()
167 {
168 $this->conf->set('translation.mode', 'php');
169 $this->conf->set('translation.extensions.test', 'tests/utils/languages/');
170 new Languages('en', $this->conf);
171 $txt = 'car'; // ignore me poedit
172 $this->assertEquals('voiture', t($txt, $txt, 1, 'test'));
173 $this->assertEquals('Fouille', t('Search', 'Search', 1, 'test'));
174 }
175}
diff --git a/tests/languages/fr/UtilsFrTest.php b/tests/languages/fr/UtilsFrTest.php
new file mode 100644
index 00000000..3dbb126f
--- /dev/null
+++ b/tests/languages/fr/UtilsFrTest.php
@@ -0,0 +1,119 @@
1<?php
2
3require_once 'tests/UtilsTest.php';
4
5
6class UtilsFrTest extends UtilsTest
7{
8 /**
9 * Test date_format().
10 */
11 public function testDateFormat()
12 {
13 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
14 $this->assertRegExp('/1 janvier 2017 (à )?10:11:12 UTC\+0?3(:00)?/', format_date($date));
15 }
16
17 /**
18 * Test date_format() without time.
19 */
20 public function testDateFormatNoTime()
21 {
22 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
23 $this->assertRegExp('/1 janvier 2017/', format_date($date, false, true));
24 }
25
26 /**
27 * Test date_format() using builtin PHP function strftime.
28 */
29 public function testDateFormatDefault()
30 {
31 $date = DateTime::createFromFormat('Ymd_His', '20170101_101112');
32 $this->assertEquals('dim. 01 janv. 2017 10:11:12 EAT', format_date($date, true, false));
33 }
34
35 /**
36 * Test date_format() using builtin PHP function strftime without time.
37 */
38 public function testDateFormatDefaultNoTime()
39 {
40 $date = DateTime::createFromFormat('Ymd_His', '20170201_101112');
41 $this->assertEquals('01/02/2017', format_date($date, false, false));
42 }
43
44 /**
45 * Test autoLocale with a simple value
46 */
47 public function testAutoLocaleValid()
48 {
49 $current = setlocale(LC_ALL, 0);
50 $header = 'de-de';
51 autoLocale($header);
52 $this->assertEquals('de_DE.utf8', setlocale(LC_ALL, 0));
53
54 setlocale(LC_ALL, $current);
55 }
56
57 /**
58 * Test autoLocale with an alternative locale value
59 */
60 public function testAutoLocaleValidAlternative()
61 {
62 $current = setlocale(LC_ALL, 0);
63 $header = 'de_de.UTF8';
64 autoLocale($header);
65 $this->assertEquals('de_DE.utf8', setlocale(LC_ALL, 0));
66
67 setlocale(LC_ALL, $current);
68 }
69
70 /**
71 * Test autoLocale with multiples value, the first one is valid
72 */
73 public function testAutoLocaleMultipleFirstValid()
74 {
75 $current = setlocale(LC_ALL, 0);
76 $header = 'de-de;en-us';
77 autoLocale($header);
78 $this->assertEquals('de_DE.utf8', setlocale(LC_ALL, 0));
79
80 setlocale(LC_ALL, $current);
81 }
82
83 /**
84 * Test autoLocale with multiples value, the second one is available
85 */
86 public function testAutoLocaleMultipleSecondAvailable()
87 {
88 $current = setlocale(LC_ALL, 0);
89 $header = 'mag_IN,de-de';
90 autoLocale($header);
91 $this->assertEquals('de_DE.utf8', setlocale(LC_ALL, 0));
92
93 setlocale(LC_ALL, $current);
94 }
95
96 /**
97 * Test autoLocale without value: defaults to en_US.
98 */
99 public function testAutoLocaleBlank()
100 {
101 $current = setlocale(LC_ALL, 0);
102 autoLocale('');
103 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
104
105 setlocale(LC_ALL, $current);
106 }
107
108 /**
109 * Test autoLocale with an unavailable value: defaults to en_US.
110 */
111 public function testAutoLocaleUnavailable()
112 {
113 $current = setlocale(LC_ALL, 0);
114 autoLocale('mag_IN');
115 $this->assertEquals('en_US.utf8', setlocale(LC_ALL, 0));
116
117 setlocale(LC_ALL, $current);
118 }
119}
diff --git a/tests/plugins/PluginAddlinkTest.php b/tests/plugins/PluginAddlinkTest.php
index a2f25bec..b6239e7f 100644
--- a/tests/plugins/PluginAddlinkTest.php
+++ b/tests/plugins/PluginAddlinkTest.php
@@ -16,7 +16,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
16 /** 16 /**
17 * Reset plugin path. 17 * Reset plugin path.
18 */ 18 */
19 function setUp() 19 public function setUp()
20 { 20 {
21 PluginManager::$PLUGINS_PATH = 'plugins'; 21 PluginManager::$PLUGINS_PATH = 'plugins';
22 } 22 }
@@ -24,7 +24,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
24 /** 24 /**
25 * Test render_header hook while logged in. 25 * Test render_header hook while logged in.
26 */ 26 */
27 function testAddlinkHeaderLoggedIn() 27 public function testAddlinkHeaderLoggedIn()
28 { 28 {
29 $str = 'stuff'; 29 $str = 'stuff';
30 $data = array($str => $str); 30 $data = array($str => $str);
@@ -46,7 +46,7 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
46 /** 46 /**
47 * Test render_header hook while logged out. 47 * Test render_header hook while logged out.
48 */ 48 */
49 function testAddlinkHeaderLoggedOut() 49 public function testAddlinkHeaderLoggedOut()
50 { 50 {
51 $str = 'stuff'; 51 $str = 'stuff';
52 $data = array($str => $str); 52 $data = array($str => $str);
@@ -57,44 +57,4 @@ class PluginAddlinkTest extends PHPUnit_Framework_TestCase
57 $this->assertEquals($str, $data[$str]); 57 $this->assertEquals($str, $data[$str]);
58 $this->assertArrayNotHasKey('fields_toolbar', $data); 58 $this->assertArrayNotHasKey('fields_toolbar', $data);
59 } 59 }
60
61 /**
62 * Test render_includes hook while logged in.
63 */
64 function testAddlinkIncludesLoggedIn()
65 {
66 $str = 'stuff';
67 $data = array($str => $str);
68 $data['_PAGE_'] = Router::$PAGE_LINKLIST;
69 $data['_LOGGEDIN_'] = true;
70
71 $data = hook_addlink_toolbar_render_includes($data);
72 $this->assertEquals($str, $data[$str]);
73 $this->assertEquals(1, count($data['css_files']));
74
75 $str = 'stuff';
76 $data = array($str => $str);
77 $data['_PAGE_'] = $str;
78 $data['_LOGGEDIN_'] = true;
79
80 $data = hook_addlink_toolbar_render_includes($data);
81 $this->assertEquals($str, $data[$str]);
82 $this->assertArrayNotHasKey('css_files', $data);
83 }
84
85 /**
86 * Test render_includes hook.
87 * Should not affect css files while logged out.
88 */
89 function testAddlinkIncludesLoggedOut()
90 {
91 $str = 'stuff';
92 $data = array($str => $str);
93 $data['_PAGE_'] = Router::$PAGE_LINKLIST;
94 $data['_LOGGEDIN_'] = false;
95
96 $data = hook_addlink_toolbar_render_includes($data);
97 $this->assertEquals($str, $data[$str]);
98 $this->assertArrayNotHasKey('css_files', $data);
99 }
100} 60}
diff --git a/tests/plugins/PluginArchiveorgTest.php b/tests/plugins/PluginArchiveorgTest.php
index 4daa4c9d..fecd5f2c 100644
--- a/tests/plugins/PluginArchiveorgTest.php
+++ b/tests/plugins/PluginArchiveorgTest.php
@@ -15,7 +15,7 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
15 /** 15 /**
16 * Reset plugin path 16 * Reset plugin path
17 */ 17 */
18 function setUp() 18 public function setUp()
19 { 19 {
20 PluginManager::$PLUGINS_PATH = 'plugins'; 20 PluginManager::$PLUGINS_PATH = 'plugins';
21 } 21 }
@@ -23,7 +23,7 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
23 /** 23 /**
24 * Test render_linklist hook on external links. 24 * Test render_linklist hook on external links.
25 */ 25 */
26 function testArchiveorgLinklistOnExternalLinks() 26 public function testArchiveorgLinklistOnExternalLinks()
27 { 27 {
28 $str = 'http://randomstr.com/test'; 28 $str = 'http://randomstr.com/test';
29 29
@@ -48,13 +48,12 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
48 // plugin data 48 // plugin data
49 $this->assertEquals(1, count($link['link_plugin'])); 49 $this->assertEquals(1, count($link['link_plugin']));
50 $this->assertNotFalse(strpos($link['link_plugin'][0], $str)); 50 $this->assertNotFalse(strpos($link['link_plugin'][0], $str));
51
52 } 51 }
53 52
54 /** 53 /**
55 * Test render_linklist hook on internal links. 54 * Test render_linklist hook on internal links.
56 */ 55 */
57 function testArchiveorgLinklistOnInternalLinks() 56 public function testArchiveorgLinklistOnInternalLinks()
58 { 57 {
59 $internalLink1 = 'http://shaarli.shaarli/?qvMAqg'; 58 $internalLink1 = 'http://shaarli.shaarli/?qvMAqg';
60 $internalLinkRealURL1 = '?qvMAqg'; 59 $internalLinkRealURL1 = '?qvMAqg';
@@ -101,7 +100,6 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
101 ) 100 )
102 ); 101 );
103 102
104
105 $data = hook_archiveorg_render_linklist($data); 103 $data = hook_archiveorg_render_linklist($data);
106 104
107 // Case n°1: first link type, public 105 // Case n°1: first link type, public
@@ -136,7 +134,5 @@ class PluginArchiveorgTest extends PHPUnit_Framework_TestCase
136 $link = $data['links'][5]; 134 $link = $data['links'][5];
137 135
138 $this->assertArrayNotHasKey('link_plugin', $link); 136 $this->assertArrayNotHasKey('link_plugin', $link);
139
140 } 137 }
141
142} 138}
diff --git a/tests/plugins/PluginIssoTest.php b/tests/plugins/PluginIssoTest.php
index 6b7904dd..0ae73183 100644
--- a/tests/plugins/PluginIssoTest.php
+++ b/tests/plugins/PluginIssoTest.php
@@ -1,4 +1,5 @@
1<?php 1<?php
2use Shaarli\Config\ConfigManager;
2 3
3require_once 'plugins/isso/isso.php'; 4require_once 'plugins/isso/isso.php';
4 5
@@ -12,7 +13,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
12 /** 13 /**
13 * Reset plugin path 14 * Reset plugin path
14 */ 15 */
15 function setUp() 16 public function setUp()
16 { 17 {
17 PluginManager::$PLUGINS_PATH = 'plugins'; 18 PluginManager::$PLUGINS_PATH = 'plugins';
18 } 19 }
@@ -20,7 +21,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
20 /** 21 /**
21 * Test Isso init without errors. 22 * Test Isso init without errors.
22 */ 23 */
23 function testWallabagInitNoError() 24 public function testWallabagInitNoError()
24 { 25 {
25 $conf = new ConfigManager(''); 26 $conf = new ConfigManager('');
26 $conf->set('plugins.ISSO_SERVER', 'value'); 27 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -31,7 +32,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
31 /** 32 /**
32 * Test Isso init with errors. 33 * Test Isso init with errors.
33 */ 34 */
34 function testWallabagInitError() 35 public function testWallabagInitError()
35 { 36 {
36 $conf = new ConfigManager(''); 37 $conf = new ConfigManager('');
37 $errors = isso_init($conf); 38 $errors = isso_init($conf);
@@ -41,7 +42,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
41 /** 42 /**
42 * Test render_linklist hook with valid settings to display the comment form. 43 * Test render_linklist hook with valid settings to display the comment form.
43 */ 44 */
44 function testIssoDisplayed() 45 public function testIssoDisplayed()
45 { 46 {
46 $conf = new ConfigManager(''); 47 $conf = new ConfigManager('');
47 $conf->set('plugins.ISSO_SERVER', 'value'); 48 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -81,7 +82,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
81 /** 82 /**
82 * Test isso plugin when multiple links are displayed (shouldn't be displayed). 83 * Test isso plugin when multiple links are displayed (shouldn't be displayed).
83 */ 84 */
84 function testIssoMultipleLinks() 85 public function testIssoMultipleLinks()
85 { 86 {
86 $conf = new ConfigManager(''); 87 $conf = new ConfigManager('');
87 $conf->set('plugins.ISSO_SERVER', 'value'); 88 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -113,7 +114,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
113 /** 114 /**
114 * Test isso plugin when using search (shouldn't be displayed). 115 * Test isso plugin when using search (shouldn't be displayed).
115 */ 116 */
116 function testIssoNotDisplayedWhenSearch() 117 public function testIssoNotDisplayedWhenSearch()
117 { 118 {
118 $conf = new ConfigManager(''); 119 $conf = new ConfigManager('');
119 $conf->set('plugins.ISSO_SERVER', 'value'); 120 $conf->set('plugins.ISSO_SERVER', 'value');
@@ -141,7 +142,7 @@ class PluginIssoTest extends PHPUnit_Framework_TestCase
141 /** 142 /**
142 * Test isso plugin without server configuration (shouldn't be displayed). 143 * Test isso plugin without server configuration (shouldn't be displayed).
143 */ 144 */
144 function testIssoWithoutConf() 145 public function testIssoWithoutConf()
145 { 146 {
146 $data = 'abc'; 147 $data = 'abc';
147 $conf = new ConfigManager(''); 148 $conf = new ConfigManager('');
diff --git a/tests/plugins/PluginMarkdownTest.php b/tests/plugins/PluginMarkdownTest.php
index f1e1acf8..96891f1f 100644
--- a/tests/plugins/PluginMarkdownTest.php
+++ b/tests/plugins/PluginMarkdownTest.php
@@ -1,4 +1,5 @@
1<?php 1<?php
2use Shaarli\Config\ConfigManager;
2 3
3/** 4/**
4 * PluginMarkdownTest.php 5 * PluginMarkdownTest.php
@@ -21,17 +22,18 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
21 /** 22 /**
22 * Reset plugin path 23 * Reset plugin path
23 */ 24 */
24 function setUp() 25 public function setUp()
25 { 26 {
26 PluginManager::$PLUGINS_PATH = 'plugins'; 27 PluginManager::$PLUGINS_PATH = 'plugins';
27 $this->conf = new ConfigManager('tests/utils/config/configJson'); 28 $this->conf = new ConfigManager('tests/utils/config/configJson');
29 $this->conf->set('security.allowed_protocols', ['ftp', 'magnet']);
28 } 30 }
29 31
30 /** 32 /**
31 * Test render_linklist hook. 33 * Test render_linklist hook.
32 * Only check that there is basic markdown rendering. 34 * Only check that there is basic markdown rendering.
33 */ 35 */
34 function testMarkdownLinklist() 36 public function testMarkdownLinklist()
35 { 37 {
36 $markdown = '# My title' . PHP_EOL . 'Very interesting content.'; 38 $markdown = '# My title' . PHP_EOL . 'Very interesting content.';
37 $data = array( 39 $data = array(
@@ -51,7 +53,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
51 * Test render_daily hook. 53 * Test render_daily hook.
52 * Only check that there is basic markdown rendering. 54 * Only check that there is basic markdown rendering.
53 */ 55 */
54 function testMarkdownDaily() 56 public function testMarkdownDaily()
55 { 57 {
56 $markdown = '# My title' . PHP_EOL . 'Very interesting content.'; 58 $markdown = '# My title' . PHP_EOL . 'Very interesting content.';
57 $data = array( 59 $data = array(
@@ -75,7 +77,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
75 /** 77 /**
76 * Test reverse_text2clickable(). 78 * Test reverse_text2clickable().
77 */ 79 */
78 function testReverseText2clickable() 80 public function testReverseText2clickable()
79 { 81 {
80 $text = 'stuff http://hello.there/is=someone#here otherstuff'; 82 $text = 'stuff http://hello.there/is=someone#here otherstuff';
81 $clickableText = text2clickable($text, ''); 83 $clickableText = text2clickable($text, '');
@@ -86,7 +88,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
86 /** 88 /**
87 * Test reverse_nl2br(). 89 * Test reverse_nl2br().
88 */ 90 */
89 function testReverseNl2br() 91 public function testReverseNl2br()
90 { 92 {
91 $text = 'stuff' . PHP_EOL . 'otherstuff'; 93 $text = 'stuff' . PHP_EOL . 'otherstuff';
92 $processedText = nl2br($text); 94 $processedText = nl2br($text);
@@ -97,7 +99,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
97 /** 99 /**
98 * Test reverse_space2nbsp(). 100 * Test reverse_space2nbsp().
99 */ 101 */
100 function testReverseSpace2nbsp() 102 public function testReverseSpace2nbsp()
101 { 103 {
102 $text = ' stuff' . PHP_EOL . ' otherstuff and another'; 104 $text = ' stuff' . PHP_EOL . ' otherstuff and another';
103 $processedText = space2nbsp($text); 105 $processedText = space2nbsp($text);
@@ -108,7 +110,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
108 /** 110 /**
109 * Test sanitize_html(). 111 * Test sanitize_html().
110 */ 112 */
111 function testSanitizeHtml() 113 public function testSanitizeHtml()
112 { 114 {
113 $input = '< script src="js.js"/>'; 115 $input = '< script src="js.js"/>';
114 $input .= '< script attr>alert(\'xss\');</script>'; 116 $input .= '< script attr>alert(\'xss\');</script>';
@@ -127,7 +129,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
127 /** 129 /**
128 * Test the no markdown tag. 130 * Test the no markdown tag.
129 */ 131 */
130 function testNoMarkdownTag() 132 public function testNoMarkdownTag()
131 { 133 {
132 $str = 'All _work_ and `no play` makes Jack a *dull* boy.'; 134 $str = 'All _work_ and `no play` makes Jack a *dull* boy.';
133 $data = array( 135 $data = array(
@@ -166,7 +168,7 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
166 /** 168 /**
167 * Test that a close value to nomarkdown is not understand as nomarkdown (previous value `.nomarkdown`). 169 * Test that a close value to nomarkdown is not understand as nomarkdown (previous value `.nomarkdown`).
168 */ 170 */
169 function testNoMarkdownNotExcactlyMatching() 171 public function testNoMarkdownNotExcactlyMatching()
170 { 172 {
171 $str = 'All _work_ and `no play` makes Jack a *dull* boy.'; 173 $str = 'All _work_ and `no play` makes Jack a *dull* boy.';
172 $data = array( 174 $data = array(
@@ -182,15 +184,19 @@ class PluginMarkdownTest extends PHPUnit_Framework_TestCase
182 } 184 }
183 185
184 /** 186 /**
185 * Test hashtag links processed with markdown. 187 * Make sure that the generated HTML match the reference HTML file.
186 */ 188 */
187 function testMarkdownHashtagLinks() 189 public function testMarkdownGlobalProcessDescription()
188 { 190 {
189 $md = file_get_contents('tests/plugins/resources/markdown.md'); 191 $md = file_get_contents('tests/plugins/resources/markdown.md');
190 $md = format_description($md); 192 $md = format_description($md);
191 $html = file_get_contents('tests/plugins/resources/markdown.html'); 193 $html = file_get_contents('tests/plugins/resources/markdown.html');
192 194
193 $data = process_markdown($md); 195 $data = process_markdown(
196 $md,
197 $this->conf->get('security.markdown_escape', true),
198 $this->conf->get('security.allowed_protocols')
199 );
194 $this->assertEquals($html, $data); 200 $this->assertEquals($html, $data);
195 } 201 }
196 202
diff --git a/tests/plugins/PluginPlayvideosTest.php b/tests/plugins/PluginPlayvideosTest.php
index be1ef774..29ad047f 100644
--- a/tests/plugins/PluginPlayvideosTest.php
+++ b/tests/plugins/PluginPlayvideosTest.php
@@ -16,7 +16,7 @@ class PluginPlayvideosTest extends PHPUnit_Framework_TestCase
16 /** 16 /**
17 * Reset plugin path 17 * Reset plugin path
18 */ 18 */
19 function setUp() 19 public function setUp()
20 { 20 {
21 PluginManager::$PLUGINS_PATH = 'plugins'; 21 PluginManager::$PLUGINS_PATH = 'plugins';
22 } 22 }
@@ -24,7 +24,7 @@ class PluginPlayvideosTest extends PHPUnit_Framework_TestCase
24 /** 24 /**
25 * Test render_linklist hook. 25 * Test render_linklist hook.
26 */ 26 */
27 function testPlayvideosHeader() 27 public function testPlayvideosHeader()
28 { 28 {
29 $str = 'stuff'; 29 $str = 'stuff';
30 $data = array($str => $str); 30 $data = array($str => $str);
@@ -43,7 +43,7 @@ class PluginPlayvideosTest extends PHPUnit_Framework_TestCase
43 /** 43 /**
44 * Test render_footer hook. 44 * Test render_footer hook.
45 */ 45 */
46 function testPlayvideosFooter() 46 public function testPlayvideosFooter()
47 { 47 {
48 $str = 'stuff'; 48 $str = 'stuff';
49 $data = array($str => $str); 49 $data = array($str => $str);
diff --git a/tests/plugins/PluginPubsubhubbubTest.php b/tests/plugins/PluginPubsubhubbubTest.php
new file mode 100644
index 00000000..69d00936
--- /dev/null
+++ b/tests/plugins/PluginPubsubhubbubTest.php
@@ -0,0 +1,55 @@
1<?php
2use Shaarli\Config\ConfigManager;
3
4require_once 'plugins/pubsubhubbub/pubsubhubbub.php';
5require_once 'application/Router.php';
6
7/**
8 * Class PluginPubsubhubbubTest
9 * Unit test for the pubsubhubbub plugin
10 */
11class PluginPubsubhubbubTest extends PHPUnit_Framework_TestCase
12{
13 /**
14 * @var string Config file path (without extension).
15 */
16 protected static $configFile = 'tests/utils/config/configJson';
17
18 /**
19 * Reset plugin path
20 */
21 public function setUp()
22 {
23 PluginManager::$PLUGINS_PATH = 'plugins';
24 }
25
26 /**
27 * Test render_feed hook with an RSS feed.
28 */
29 public function testPubSubRssRenderFeed()
30 {
31 $hub = 'http://domain.hub';
32 $conf = new ConfigManager(self::$configFile);
33 $conf->set('plugins.PUBSUBHUB_URL', $hub);
34 $data['_PAGE_'] = Router::$PAGE_FEED_RSS;
35
36 $data = hook_pubsubhubbub_render_feed($data, $conf);
37 $expected = '<atom:link rel="hub" href="'. $hub .'" />';
38 $this->assertEquals($expected, $data['feed_plugins_header'][0]);
39 }
40
41 /**
42 * Test render_feed hook with an ATOM feed.
43 */
44 public function testPubSubAtomRenderFeed()
45 {
46 $hub = 'http://domain.hub';
47 $conf = new ConfigManager(self::$configFile);
48 $conf->set('plugins.PUBSUBHUB_URL', $hub);
49 $data['_PAGE_'] = Router::$PAGE_FEED_ATOM;
50
51 $data = hook_pubsubhubbub_render_feed($data, $conf);
52 $expected = '<link rel="hub" href="'. $hub .'" />';
53 $this->assertEquals($expected, $data['feed_plugins_header'][0]);
54 }
55}
diff --git a/tests/plugins/PlugQrcodeTest.php b/tests/plugins/PluginQrcodeTest.php
index 86dc7f29..ebfadddf 100644
--- a/tests/plugins/PlugQrcodeTest.php
+++ b/tests/plugins/PluginQrcodeTest.php
@@ -1,29 +1,28 @@
1<?php 1<?php
2
3/** 2/**
4 * PlugQrcodeTest.php 3 * PluginQrcodeTest.php
5 */ 4 */
6 5
7require_once 'plugins/qrcode/qrcode.php'; 6require_once 'plugins/qrcode/qrcode.php';
8require_once 'application/Router.php'; 7require_once 'application/Router.php';
9 8
10/** 9/**
11 * Class PlugQrcodeTest 10 * Class PluginQrcodeTest
12 * Unit test for the QR-Code plugin 11 * Unit test for the QR-Code plugin
13 */ 12 */
14class PlugQrcodeTest extends PHPUnit_Framework_TestCase 13class PluginQrcodeTest extends PHPUnit_Framework_TestCase
15{ 14{
16 /** 15 /**
17 * Reset plugin path 16 * Reset plugin path
18 */ 17 */
19 function setUp() { 18 public function setUp() {
20 PluginManager::$PLUGINS_PATH = 'plugins'; 19 PluginManager::$PLUGINS_PATH = 'plugins';
21 } 20 }
22 21
23 /** 22 /**
24 * Test render_linklist hook. 23 * Test render_linklist hook.
25 */ 24 */
26 function testQrcodeLinklist() 25 public function testQrcodeLinklist()
27 { 26 {
28 $str = 'http://randomstr.com/test'; 27 $str = 'http://randomstr.com/test';
29 $data = array( 28 $data = array(
@@ -49,7 +48,7 @@ class PlugQrcodeTest extends PHPUnit_Framework_TestCase
49 /** 48 /**
50 * Test render_footer hook. 49 * Test render_footer hook.
51 */ 50 */
52 function testQrcodeFooter() 51 public function testQrcodeFooter()
53 { 52 {
54 $str = 'stuff'; 53 $str = 'stuff';
55 $data = array($str => $str); 54 $data = array($str => $str);
diff --git a/tests/plugins/PluginReadityourselfTest.php b/tests/plugins/PluginReadityourselfTest.php
deleted file mode 100644
index 532db146..00000000
--- a/tests/plugins/PluginReadityourselfTest.php
+++ /dev/null
@@ -1,98 +0,0 @@
1<?php
2
3/**
4 * PluginReadityourselfTest.php.php
5 */
6
7require_once 'plugins/readityourself/readityourself.php';
8
9/**
10 * Class PluginWallabagTest
11 * Unit test for the Wallabag plugin
12 */
13class PluginReadityourselfTest extends PHPUnit_Framework_TestCase
14{
15 /**
16 * Reset plugin path
17 */
18 function setUp()
19 {
20 PluginManager::$PLUGINS_PATH = 'plugins';
21 }
22
23 /**
24 * Test Readityourself init without errors.
25 */
26 function testReadityourselfInitNoError()
27 {
28 $conf = new ConfigManager('');
29 $conf->set('plugins.READITYOUSELF_URL', 'value');
30 $errors = readityourself_init($conf);
31 $this->assertEmpty($errors);
32 }
33
34 /**
35 * Test Readityourself init with errors.
36 */
37 function testReadityourselfInitError()
38 {
39 $conf = new ConfigManager('');
40 $errors = readityourself_init($conf);
41 $this->assertNotEmpty($errors);
42 }
43
44 /**
45 * Test render_linklist hook.
46 */
47 function testReadityourselfLinklist()
48 {
49 $conf = new ConfigManager('');
50 $conf->set('plugins.READITYOUSELF_URL', 'value');
51 $str = 'http://randomstr.com/test';
52 $data = array(
53 'title' => $str,
54 'links' => array(
55 array(
56 'url' => $str,
57 )
58 )
59 );
60
61 $data = hook_readityourself_render_linklist($data, $conf);
62 $link = $data['links'][0];
63 // data shouldn't be altered
64 $this->assertEquals($str, $data['title']);
65 $this->assertEquals($str, $link['url']);
66
67 // plugin data
68 $this->assertEquals(1, count($link['link_plugin']));
69 $this->assertNotFalse(strpos($link['link_plugin'][0], $str));
70 }
71
72 /**
73 * Test without config: nothing should happened.
74 */
75 function testReadityourselfLinklistWithoutConfig()
76 {
77 $conf = new ConfigManager('');
78 $conf->set('plugins.READITYOUSELF_URL', null);
79 $str = 'http://randomstr.com/test';
80 $data = array(
81 'title' => $str,
82 'links' => array(
83 array(
84 'url' => $str,
85 )
86 )
87 );
88
89 $data = hook_readityourself_render_linklist($data, $conf);
90 $link = $data['links'][0];
91 // data shouldn't be altered
92 $this->assertEquals($str, $data['title']);
93 $this->assertEquals($str, $link['url']);
94
95 // plugin data
96 $this->assertArrayNotHasKey('link_plugin', $link);
97 }
98}
diff --git a/tests/plugins/PluginWallabagTest.php b/tests/plugins/PluginWallabagTest.php
index 2c268cbd..76b7887e 100644
--- a/tests/plugins/PluginWallabagTest.php
+++ b/tests/plugins/PluginWallabagTest.php
@@ -1,4 +1,5 @@
1<?php 1<?php
2use Shaarli\Config\ConfigManager;
2 3
3/** 4/**
4 * PluginWallabagTest.php.php 5 * PluginWallabagTest.php.php
@@ -15,7 +16,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
15 /** 16 /**
16 * Reset plugin path 17 * Reset plugin path
17 */ 18 */
18 function setUp() 19 public function setUp()
19 { 20 {
20 PluginManager::$PLUGINS_PATH = 'plugins'; 21 PluginManager::$PLUGINS_PATH = 'plugins';
21 } 22 }
@@ -23,7 +24,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
23 /** 24 /**
24 * Test wallabag init without errors. 25 * Test wallabag init without errors.
25 */ 26 */
26 function testWallabagInitNoError() 27 public function testWallabagInitNoError()
27 { 28 {
28 $conf = new ConfigManager(''); 29 $conf = new ConfigManager('');
29 $conf->set('plugins.WALLABAG_URL', 'value'); 30 $conf->set('plugins.WALLABAG_URL', 'value');
@@ -34,7 +35,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
34 /** 35 /**
35 * Test wallabag init with errors. 36 * Test wallabag init with errors.
36 */ 37 */
37 function testWallabagInitError() 38 public function testWallabagInitError()
38 { 39 {
39 $conf = new ConfigManager(''); 40 $conf = new ConfigManager('');
40 $errors = wallabag_init($conf); 41 $errors = wallabag_init($conf);
@@ -44,7 +45,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase
44 /** 45 /**
45 * Test render_linklist hook. 46 * Test render_linklist hook.
46 */ 47 */
47 function testWallabagLinklist() 48 public function testWallabagLinklist()
48 { 49 {
49 $conf = new ConfigManager(''); 50 $conf = new ConfigManager('');
50 $conf->set('plugins.WALLABAG_URL', 'value'); 51 $conf->set('plugins.WALLABAG_URL', 'value');
diff --git a/tests/plugins/WallabagInstanceTest.php b/tests/plugins/WallabagInstanceTest.php
index 7c14c1df..2c466871 100644
--- a/tests/plugins/WallabagInstanceTest.php
+++ b/tests/plugins/WallabagInstanceTest.php
@@ -15,7 +15,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
15 /** 15 /**
16 * Reset plugin path 16 * Reset plugin path
17 */ 17 */
18 function setUp() 18 public function setUp()
19 { 19 {
20 $this->instance = 'http://some.url'; 20 $this->instance = 'http://some.url';
21 } 21 }
@@ -23,7 +23,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
23 /** 23 /**
24 * Test WallabagInstance with API V1. 24 * Test WallabagInstance with API V1.
25 */ 25 */
26 function testWallabagInstanceV1() 26 public function testWallabagInstanceV1()
27 { 27 {
28 $instance = new WallabagInstance($this->instance, 1); 28 $instance = new WallabagInstance($this->instance, 1);
29 $expected = $this->instance . '/?plainurl='; 29 $expected = $this->instance . '/?plainurl=';
@@ -34,7 +34,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
34 /** 34 /**
35 * Test WallabagInstance with API V2. 35 * Test WallabagInstance with API V2.
36 */ 36 */
37 function testWallabagInstanceV2() 37 public function testWallabagInstanceV2()
38 { 38 {
39 $instance = new WallabagInstance($this->instance, 2); 39 $instance = new WallabagInstance($this->instance, 2);
40 $expected = $this->instance . '/bookmarklet?url='; 40 $expected = $this->instance . '/bookmarklet?url=';
@@ -45,7 +45,7 @@ class WallabagInstanceTest extends PHPUnit_Framework_TestCase
45 /** 45 /**
46 * Test WallabagInstance with an invalid API version. 46 * Test WallabagInstance with an invalid API version.
47 */ 47 */
48 function testWallabagInstanceInvalidVersion() 48 public function testWallabagInstanceInvalidVersion()
49 { 49 {
50 $instance = new WallabagInstance($this->instance, false); 50 $instance = new WallabagInstance($this->instance, false);
51 $expected = $this->instance . '/?plainurl='; 51 $expected = $this->instance . '/?plainurl=';
diff --git a/tests/plugins/resources/markdown.html b/tests/plugins/resources/markdown.html
index 07a5a32e..844a6f31 100644
--- a/tests/plugins/resources/markdown.html
+++ b/tests/plugins/resources/markdown.html
@@ -21,4 +21,13 @@
21next #foo</code></pre> 21next #foo</code></pre>
22<p>Block:</p> 22<p>Block:</p>
23<pre><code>lorem ipsum #foobar http://link.tld 23<pre><code>lorem ipsum #foobar http://link.tld
24#foobar http://link.tld</code></pre></div> \ No newline at end of file 24#foobar http://link.tld</code></pre>
25<p><a href="?123456">link</a><br />
26<img src="/img/train.png" alt="link" /><br />
27<a href="http://test.tld/path/?query=value#hash">link</a><br />
28<a href="http://test.tld/path/?query=value#hash">link</a><br />
29<a href="https://test.tld/path/?query=value#hash">link</a><br />
30<a href="ftp://test.tld/path/?query=value#hash">link</a><br />
31<a href="magnet:test.tld/path/?query=value#hash">link</a><br />
32<a href="http://alert('xss')">link</a><br />
33<a href="http://test.tld/path/?query=value#hash">link</a></p></div> \ No newline at end of file
diff --git a/tests/plugins/resources/markdown.md b/tests/plugins/resources/markdown.md
index 0b8be7c5..b8ebd934 100644
--- a/tests/plugins/resources/markdown.md
+++ b/tests/plugins/resources/markdown.md
@@ -21,4 +21,14 @@ Block:
21``` 21```
22lorem ipsum #foobar http://link.tld 22lorem ipsum #foobar http://link.tld
23#foobar http://link.tld 23#foobar http://link.tld
24``` \ No newline at end of file 24```
25
26[link](?123456)
27![link](/img/train.png)
28[link](test.tld/path/?query=value#hash)
29[link](http://test.tld/path/?query=value#hash)
30[link](https://test.tld/path/?query=value#hash)
31[link](ftp://test.tld/path/?query=value#hash)
32[link](magnet:test.tld/path/?query=value#hash)
33[link](javascript:alert('xss'))
34[link](other://test.tld/path/?query=value#hash) \ No newline at end of file
diff --git a/tests/utils/FakeConfigManager.php b/tests/utils/FakeConfigManager.php
new file mode 100644
index 00000000..f29760cb
--- /dev/null
+++ b/tests/utils/FakeConfigManager.php
@@ -0,0 +1,12 @@
1<?php
2
3/**
4 * Fake ConfigManager
5 */
6class FakeConfigManager
7{
8 public static function get($key)
9 {
10 return $key;
11 }
12}
diff --git a/tests/utils/ReferenceHistory.php b/tests/utils/ReferenceHistory.php
new file mode 100644
index 00000000..75cbb326
--- /dev/null
+++ b/tests/utils/ReferenceHistory.php
@@ -0,0 +1,82 @@
1<?php
2
3/**
4 * Populates a reference history
5 */
6class ReferenceHistory
7{
8 private $count;
9
10 private $history = [];
11
12 /**
13 * Populates the test DB with reference data
14 */
15 public function __construct()
16 {
17 $this->addEntry(
18 History::DELETED,
19 DateTime::createFromFormat('Ymd_His', '20170303_121216'),
20 124
21 );
22
23 $this->addEntry(
24 History::SETTINGS,
25 DateTime::createFromFormat('Ymd_His', '20170302_121215')
26 );
27
28 $this->addEntry(
29 History::UPDATED,
30 DateTime::createFromFormat('Ymd_His', '20170301_121214'),
31 123
32 );
33
34 $this->addEntry(
35 History::CREATED,
36 DateTime::createFromFormat('Ymd_His', '20170201_121214'),
37 124
38 );
39
40 $this->addEntry(
41 History::CREATED,
42 DateTime::createFromFormat('Ymd_His', '20170101_121212'),
43 123
44 );
45 }
46
47 /**
48 * Adds a new history entry
49 *
50 * @param string $event Event identifier
51 * @param DateTime $datetime creation date
52 * @param int $id optional: related link ID
53 */
54 protected function addEntry($event, $datetime, $id = null)
55 {
56 $link = [
57 'event' => $event,
58 'datetime' => $datetime,
59 'id' => $id,
60 ];
61 $this->history[] = $link;
62 $this->count++;
63 }
64
65 /**
66 * Writes data to the datastore
67 *
68 * @param string $filename write history content to.
69 */
70 public function write($filename)
71 {
72 FileUtils::writeFlatDB($filename, $this->history);
73 }
74
75 /**
76 * Returns the number of links in the reference data
77 */
78 public function count()
79 {
80 return $this->count;
81 }
82}
diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php
index 36d58c68..e887aa78 100644
--- a/tests/utils/ReferenceLinkDB.php
+++ b/tests/utils/ReferenceLinkDB.php
@@ -4,7 +4,7 @@
4 */ 4 */
5class ReferenceLinkDB 5class ReferenceLinkDB
6{ 6{
7 public static $NB_LINKS_TOTAL = 8; 7 public static $NB_LINKS_TOTAL = 9;
8 8
9 private $_links = array(); 9 private $_links = array();
10 private $_publicCount = 0; 10 private $_publicCount = 0;
@@ -38,6 +38,16 @@ class ReferenceLinkDB
38 ); 38 );
39 39
40 $this->addLink( 40 $this->addLink(
41 9,
42 'PSR-2: Coding Style Guide',
43 'http://www.php-fig.org/psr/psr-2/',
44 'This guide extends and expands on PSR-1, the basic coding standard.',
45 0,
46 DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121206_152312'),
47 ''
48 );
49
50 $this->addLink(
41 8, 51 8,
42 'Free as in Freedom 2.0 @website', 52 'Free as in Freedom 2.0 @website',
43 'https://static.fsf.org/nosvn/faif-2.0.pdf', 53 'https://static.fsf.org/nosvn/faif-2.0.pdf',
@@ -56,7 +66,7 @@ class ReferenceLinkDB
56 0, 66 0,
57 DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20130614_184135'), 67 DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20130614_184135'),
58 'gnu media web .hidden hashtag', 68 'gnu media web .hidden hashtag',
59 null, 69 DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20130615_184230'),
60 'IuWvgA' 70 'IuWvgA'
61 ); 71 );
62 72
@@ -131,6 +141,7 @@ class ReferenceLinkDB
131 */ 141 */
132 public function write($filename) 142 public function write($filename)
133 { 143 {
144 $this->reorder();
134 file_put_contents( 145 file_put_contents(
135 $filename, 146 $filename,
136 '<?php /* '.base64_encode(gzdeflate(serialize($this->_links))).' */ ?>' 147 '<?php /* '.base64_encode(gzdeflate(serialize($this->_links))).' */ ?>'
@@ -138,6 +149,27 @@ class ReferenceLinkDB
138 } 149 }
139 150
140 /** 151 /**
152 * Reorder links by creation date (newest first).
153 *
154 * Also update the urls and ids mapping arrays.
155 *
156 * @param string $order ASC|DESC
157 */
158 public function reorder($order = 'DESC')
159 {
160 // backward compatibility: ignore reorder if the the `created` field doesn't exist
161 if (! isset(array_values($this->_links)[0]['created'])) {
162 return;
163 }
164
165 $order = $order === 'ASC' ? -1 : 1;
166 // Reorder array by dates.
167 usort($this->_links, function($a, $b) use ($order) {
168 return $a['created'] < $b['created'] ? 1 * $order : -1 * $order;
169 });
170 }
171
172 /**
141 * Returns the number of links in the reference data 173 * Returns the number of links in the reference data
142 */ 174 */
143 public function countLinks() 175 public function countLinks()
@@ -161,8 +193,23 @@ class ReferenceLinkDB
161 return $this->_privateCount; 193 return $this->_privateCount;
162 } 194 }
163 195
196 /**
197 * Returns the number of links without tag
198 */
199 public function countUntaggedLinks()
200 {
201 $cpt = 0;
202 foreach ($this->_links as $link) {
203 if (empty($link['tags'])) {
204 ++$cpt;
205 }
206 }
207 return $cpt;
208 }
209
164 public function getLinks() 210 public function getLinks()
165 { 211 {
212 $this->reorder();
166 return $this->_links; 213 return $this->_links;
167 } 214 }
168 215
diff --git a/tests/utils/config/configJson.json.php b/tests/utils/config/configJson.json.php
index 06a302e8..9c9288f3 100644
--- a/tests/utils/config/configJson.json.php
+++ b/tests/utils/config/configJson.json.php
@@ -24,7 +24,8 @@
24 }, 24 },
25 "resource": { 25 "resource": {
26 "datastore": "tests\/utils\/config\/datastore.php", 26 "datastore": "tests\/utils\/config\/datastore.php",
27 "data_dir": "tests\/utils\/config" 27 "data_dir": "sandbox/",
28 "raintpl_tpl": "tpl/"
28 }, 29 },
29 "plugins": { 30 "plugins": {
30 "WALLABAG_VERSION": 1 31 "WALLABAG_VERSION": 1
diff --git a/tests/utils/config/emptyConfigPhp.php b/tests/utils/config/emptyConfigPhp.php
new file mode 100644
index 00000000..b3d9bbc7
--- /dev/null
+++ b/tests/utils/config/emptyConfigPhp.php
@@ -0,0 +1 @@
<?php
diff --git a/tests/utils/languages/fr/LC_MESSAGES/test.mo b/tests/utils/languages/fr/LC_MESSAGES/test.mo
new file mode 100644
index 00000000..416c7831
--- /dev/null
+++ b/tests/utils/languages/fr/LC_MESSAGES/test.mo
Binary files differ
diff --git a/tests/utils/languages/fr/LC_MESSAGES/test.po b/tests/utils/languages/fr/LC_MESSAGES/test.po
new file mode 100644
index 00000000..89a4fd9b
--- /dev/null
+++ b/tests/utils/languages/fr/LC_MESSAGES/test.po
@@ -0,0 +1,19 @@
1msgid ""
2msgstr ""
3"Project-Id-Version: Extension test\n"
4"POT-Creation-Date: 2017-05-20 13:54+0200\n"
5"PO-Revision-Date: 2017-05-20 14:16+0200\n"
6"Last-Translator: \n"
7"Language-Team: Shaarli\n"
8"Language: fr_FR\n"
9"MIME-Version: 1.0\n"
10"Content-Type: text/plain; charset=UTF-8\n"
11"Content-Transfer-Encoding: 8bit\n"
12"Plural-Forms: nplurals=2; plural=(n > 1);\n"
13"X-Generator: Poedit 2.0.1\n"
14
15msgid "car"
16msgstr "voiture"
17
18msgid "Search"
19msgstr "Fouille"