aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/.htaccess2
-rw-r--r--tests/LinkDBTest.php509
-rw-r--r--tests/UtilsTest.php78
-rw-r--r--tests/utils/ReferenceLinkDB.php128
4 files changed, 717 insertions, 0 deletions
diff --git a/tests/.htaccess b/tests/.htaccess
new file mode 100644
index 00000000..b584d98c
--- /dev/null
+++ b/tests/.htaccess
@@ -0,0 +1,2 @@
1Allow from none
2Deny from all
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php
new file mode 100644
index 00000000..bbe4e026
--- /dev/null
+++ b/tests/LinkDBTest.php
@@ -0,0 +1,509 @@
1<?php
2/**
3 * Link datastore tests
4 */
5
6require_once 'application/LinkDB.php';
7require_once 'application/Utils.php';
8require_once 'tests/utils/ReferenceLinkDB.php';
9
10define('PHPPREFIX', '<?php /* ');
11define('PHPSUFFIX', ' */ ?>');
12
13
14/**
15 * Unitary tests for LinkDB
16 */
17class LinkDBTest extends PHPUnit_Framework_TestCase
18{
19 // datastore to test write operations
20 protected static $testDatastore = 'tests/datastore.php';
21 protected static $dummyDatastoreSHA1 = 'e3edea8ea7bb50be4bcb404df53fbb4546a7156e';
22 protected static $refDB = null;
23 protected static $publicLinkDB = null;
24 protected static $privateLinkDB = null;
25
26 /**
27 * Instantiates public and private LinkDBs with test data
28 *
29 * The reference datastore contains public and private links that
30 * will be used to test LinkDB's methods:
31 * - access filtering (public/private),
32 * - link searches:
33 * - by day,
34 * - by tag,
35 * - by text,
36 * - etc.
37 */
38 public static function setUpBeforeClass()
39 {
40 self::$refDB = new ReferenceLinkDB();
41 self::$refDB->write(self::$testDatastore, PHPPREFIX, PHPSUFFIX);
42
43 $GLOBALS['config']['DATASTORE'] = self::$testDatastore;
44 self::$publicLinkDB = new LinkDB(false);
45 self::$privateLinkDB = new LinkDB(true);
46 }
47
48 /**
49 * Resets test data for each test
50 */
51 protected function setUp()
52 {
53 $GLOBALS['config']['DATASTORE'] = self::$testDatastore;
54 if (file_exists(self::$testDatastore)) {
55 unlink(self::$testDatastore);
56 }
57 }
58
59 /**
60 * Allows to test LinkDB's private methods
61 *
62 * @see
63 * https://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html
64 * http://stackoverflow.com/a/2798203
65 */
66 protected static function getMethod($name)
67 {
68 $class = new ReflectionClass('LinkDB');
69 $method = $class->getMethod($name);
70 $method->setAccessible(true);
71 return $method;
72 }
73
74 /**
75 * Instantiate LinkDB objects - logged in user
76 */
77 public function testConstructLoggedIn()
78 {
79 new LinkDB(true);
80 $this->assertFileExists(self::$testDatastore);
81 }
82
83 /**
84 * Instantiate LinkDB objects - logged out or public instance
85 */
86 public function testConstructLoggedOut()
87 {
88 new LinkDB(false);
89 $this->assertFileExists(self::$testDatastore);
90 }
91
92 /**
93 * Attempt to instantiate a LinkDB whereas the datastore is not writable
94 *
95 * @expectedException PHPUnit_Framework_Error_Warning
96 * @expectedExceptionMessageRegExp /failed to open stream: No such file or directory/
97 */
98 public function testConstructDatastoreNotWriteable()
99 {
100 $GLOBALS['config']['DATASTORE'] = 'null/store.db';
101 new LinkDB(false);
102 }
103
104 /**
105 * The DB doesn't exist, ensure it is created with dummy content
106 */
107 public function testCheckDBNew()
108 {
109 $linkDB = new LinkDB(false);
110 unlink(self::$testDatastore);
111 $this->assertFileNotExists(self::$testDatastore);
112
113 $checkDB = self::getMethod('checkDB');
114 $checkDB->invokeArgs($linkDB, array());
115 $this->assertFileExists(self::$testDatastore);
116
117 // ensure the correct data has been written
118 $this->assertEquals(
119 self::$dummyDatastoreSHA1,
120 sha1_file(self::$testDatastore)
121 );
122 }
123
124 /**
125 * The DB exists, don't do anything
126 */
127 public function testCheckDBLoad()
128 {
129 $linkDB = new LinkDB(false);
130 $this->assertEquals(
131 self::$dummyDatastoreSHA1,
132 sha1_file(self::$testDatastore)
133 );
134
135 $checkDB = self::getMethod('checkDB');
136 $checkDB->invokeArgs($linkDB, array());
137
138 // ensure the datastore is left unmodified
139 $this->assertEquals(
140 self::$dummyDatastoreSHA1,
141 sha1_file(self::$testDatastore)
142 );
143 }
144
145 /**
146 * Load an empty DB
147 */
148 public function testReadEmptyDB()
149 {
150 file_put_contents(self::$testDatastore, PHPPREFIX.'S7QysKquBQA='.PHPSUFFIX);
151 $emptyDB = new LinkDB(false);
152 $this->assertEquals(0, sizeof($emptyDB));
153 $this->assertEquals(0, count($emptyDB));
154 }
155
156 /**
157 * Load public links from the DB
158 */
159 public function testReadPublicDB()
160 {
161 $this->assertEquals(
162 self::$refDB->countPublicLinks(),
163 sizeof(self::$publicLinkDB)
164 );
165 }
166
167 /**
168 * Load public and private links from the DB
169 */
170 public function testReadPrivateDB()
171 {
172 $this->assertEquals(
173 self::$refDB->countLinks(),
174 sizeof(self::$privateLinkDB)
175 );
176 }
177
178 /**
179 * Save the links to the DB
180 */
181 public function testSaveDB()
182 {
183 $testDB = new LinkDB(true);
184 $dbSize = sizeof($testDB);
185
186 $link = array(
187 'title'=>'an additional link',
188 'url'=>'http://dum.my',
189 'description'=>'One more',
190 'private'=>0,
191 'linkdate'=>'20150518_190000',
192 'tags'=>'unit test'
193 );
194 $testDB[$link['linkdate']] = $link;
195
196 // TODO: move PageCache to a proper class/file
197 function invalidateCaches() {}
198
199 $testDB->savedb();
200
201 $testDB = new LinkDB(true);
202 $this->assertEquals($dbSize + 1, sizeof($testDB));
203 }
204
205 /**
206 * Count existing links
207 */
208 public function testCount()
209 {
210 $this->assertEquals(
211 self::$refDB->countPublicLinks(),
212 self::$publicLinkDB->count()
213 );
214 $this->assertEquals(
215 self::$refDB->countLinks(),
216 self::$privateLinkDB->count()
217 );
218 }
219
220 /**
221 * List the days for which links have been posted
222 */
223 public function testDays()
224 {
225 $this->assertEquals(
226 ['20121206', '20130614', '20150310'],
227 self::$publicLinkDB->days()
228 );
229
230 $this->assertEquals(
231 ['20121206', '20130614', '20141125', '20150310'],
232 self::$privateLinkDB->days()
233 );
234 }
235
236 /**
237 * The URL corresponds to an existing entry in the DB
238 */
239 public function testGetKnownLinkFromURL()
240 {
241 $link = self::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
242
243 $this->assertNotEquals(false, $link);
244 $this->assertEquals(
245 'A free software media publishing platform',
246 $link['description']
247 );
248 }
249
250 /**
251 * The URL is not in the DB
252 */
253 public function testGetUnknownLinkFromURL()
254 {
255 $this->assertEquals(
256 false,
257 self::$publicLinkDB->getLinkFromUrl('http://dev.null')
258 );
259 }
260
261 /**
262 * Lists all tags
263 */
264 public function testAllTags()
265 {
266 $this->assertEquals(
267 [
268 'web' => 3,
269 'cartoon' => 2,
270 'gnu' => 2,
271 'dev' => 1,
272 'samba' => 1,
273 'media' => 1,
274 'software' => 1,
275 'stallman' => 1,
276 'free' => 1
277 ],
278 self::$publicLinkDB->allTags()
279 );
280
281 $this->assertEquals(
282 [
283 'web' => 4,
284 'cartoon' => 3,
285 'gnu' => 2,
286 'dev' => 2,
287 'samba' => 1,
288 'media' => 1,
289 'software' => 1,
290 'stallman' => 1,
291 'free' => 1,
292 'html' => 1,
293 'w3c' => 1,
294 'css' => 1,
295 'Mercurial' => 1
296 ],
297 self::$privateLinkDB->allTags()
298 );
299 }
300
301 /**
302 * Filter links using a tag
303 */
304 public function testFilterOneTag()
305 {
306 $this->assertEquals(
307 3,
308 sizeof(self::$publicLinkDB->filterTags('web', false))
309 );
310
311 $this->assertEquals(
312 4,
313 sizeof(self::$privateLinkDB->filterTags('web', false))
314 );
315 }
316
317 /**
318 * Filter links using a tag - case-sensitive
319 */
320 public function testFilterCaseSensitiveTag()
321 {
322 $this->assertEquals(
323 0,
324 sizeof(self::$privateLinkDB->filterTags('mercurial', true))
325 );
326
327 $this->assertEquals(
328 1,
329 sizeof(self::$privateLinkDB->filterTags('Mercurial', true))
330 );
331 }
332
333 /**
334 * Filter links using a tag combination
335 */
336 public function testFilterMultipleTags()
337 {
338 $this->assertEquals(
339 1,
340 sizeof(self::$publicLinkDB->filterTags('dev cartoon', false))
341 );
342
343 $this->assertEquals(
344 2,
345 sizeof(self::$privateLinkDB->filterTags('dev cartoon', false))
346 );
347 }
348
349 /**
350 * Filter links using a non-existent tag
351 */
352 public function testFilterUnknownTag()
353 {
354 $this->assertEquals(
355 0,
356 sizeof(self::$publicLinkDB->filterTags('null', false))
357 );
358 }
359
360 /**
361 * Return links for a given day
362 */
363 public function testFilterDay()
364 {
365 $this->assertEquals(
366 2,
367 sizeof(self::$publicLinkDB->filterDay('20121206'))
368 );
369
370 $this->assertEquals(
371 3,
372 sizeof(self::$privateLinkDB->filterDay('20121206'))
373 );
374 }
375
376 /**
377 * 404 - day not found
378 */
379 public function testFilterUnknownDay()
380 {
381 $this->assertEquals(
382 0,
383 sizeof(self::$publicLinkDB->filterDay('19700101'))
384 );
385
386 $this->assertEquals(
387 0,
388 sizeof(self::$privateLinkDB->filterDay('19700101'))
389 );
390 }
391
392 /**
393 * Use an invalid date format
394 */
395 public function testFilterInvalidDay()
396 {
397 $this->assertEquals(
398 0,
399 sizeof(self::$privateLinkDB->filterDay('Rainy day, dream away'))
400 );
401
402 // TODO: check input format
403 $this->assertEquals(
404 6,
405 sizeof(self::$privateLinkDB->filterDay('20'))
406 );
407 }
408
409 /**
410 * Retrieve a link entry with its hash
411 */
412 public function testFilterSmallHash()
413 {
414 $links = self::$privateLinkDB->filterSmallHash('IuWvgA');
415
416 $this->assertEquals(
417 1,
418 sizeof($links)
419 );
420
421 $this->assertEquals(
422 'MediaGoblin',
423 $links['20130614_184135']['title']
424 );
425
426 }
427
428 /**
429 * No link for this hash
430 */
431 public function testFilterUnknownSmallHash()
432 {
433 $this->assertEquals(
434 0,
435 sizeof(self::$privateLinkDB->filterSmallHash('Iblaah'))
436 );
437 }
438
439 /**
440 * Full-text search - result from a link's URL
441 */
442 public function testFilterFullTextURL()
443 {
444 $this->assertEquals(
445 2,
446 sizeof(self::$publicLinkDB->filterFullText('ars.userfriendly.org'))
447 );
448 }
449
450 /**
451 * Full-text search - result from a link's title only
452 */
453 public function testFilterFullTextTitle()
454 {
455 // use miscellaneous cases
456 $this->assertEquals(
457 2,
458 sizeof(self::$publicLinkDB->filterFullText('userfriendly -'))
459 );
460 $this->assertEquals(
461 2,
462 sizeof(self::$publicLinkDB->filterFullText('UserFriendly -'))
463 );
464 $this->assertEquals(
465 2,
466 sizeof(self::$publicLinkDB->filterFullText('uSeRFrIendlY -'))
467 );
468
469 // use miscellaneous case and offset
470 $this->assertEquals(
471 2,
472 sizeof(self::$publicLinkDB->filterFullText('RFrIendL'))
473 );
474 }
475
476 /**
477 * Full-text search - result from the link's description only
478 */
479 public function testFilterFullTextDescription()
480 {
481 $this->assertEquals(
482 1,
483 sizeof(self::$publicLinkDB->filterFullText('media publishing'))
484 );
485 }
486
487 /**
488 * Full-text search - result from the link's tags only
489 */
490 public function testFilterFullTextTags()
491 {
492 $this->assertEquals(
493 2,
494 sizeof(self::$publicLinkDB->filterFullText('gnu'))
495 );
496 }
497
498 /**
499 * Full-text search - result set from mixed sources
500 */
501 public function testFilterFullTextMixed()
502 {
503 $this->assertEquals(
504 2,
505 sizeof(self::$publicLinkDB->filterFullText('free software'))
506 );
507 }
508}
509?>
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
new file mode 100644
index 00000000..bbba99f2
--- /dev/null
+++ b/tests/UtilsTest.php
@@ -0,0 +1,78 @@
1<?php
2/**
3 * Utilities' tests
4 */
5
6require_once 'application/Utils.php';
7
8/**
9 * Unitary tests for Shaarli utilities
10 */
11class UtilsTest extends PHPUnit_Framework_TestCase
12{
13 /**
14 * Represent a link by its hash
15 */
16 public function testSmallHash()
17 {
18 $this->assertEquals('CyAAJw', smallHash('http://test.io'));
19 $this->assertEquals(6, strlen(smallHash('https://github.com')));
20 }
21
22 /**
23 * Look for a substring at the beginning of a string
24 */
25 public function testStartsWithCaseInsensitive()
26 {
27 $this->assertTrue(startsWith('Lorem ipsum', 'lorem', false));
28 $this->assertTrue(startsWith('Lorem ipsum', 'LoReM i', false));
29 }
30
31 /**
32 * Look for a substring at the beginning of a string (case-sensitive)
33 */
34 public function testStartsWithCaseSensitive()
35 {
36 $this->assertTrue(startsWith('Lorem ipsum', 'Lorem', true));
37 $this->assertFalse(startsWith('Lorem ipsum', 'lorem', true));
38 $this->assertFalse(startsWith('Lorem ipsum', 'LoReM i', true));
39 }
40
41 /**
42 * Look for a substring at the beginning of a string (Unicode)
43 */
44 public function testStartsWithSpecialChars()
45 {
46 $this->assertTrue(startsWith('å!ùµ', 'å!', false));
47 $this->assertTrue(startsWith('µ$åù', 'µ$', true));
48 }
49
50 /**
51 * Look for a substring at the end of a string
52 */
53 public function testEndsWithCaseInsensitive()
54 {
55 $this->assertTrue(endsWith('Lorem ipsum', 'ipsum', false));
56 $this->assertTrue(endsWith('Lorem ipsum', 'm IpsUM', false));
57 }
58
59 /**
60 * Look for a substring at the end of a string (case-sensitive)
61 */
62 public function testEndsWithCaseSensitive()
63 {
64 $this->assertTrue(endsWith('lorem Ipsum', 'Ipsum', true));
65 $this->assertFalse(endsWith('lorem Ipsum', 'ipsum', true));
66 $this->assertFalse(endsWith('lorem Ipsum', 'M IPsuM', true));
67 }
68
69 /**
70 * Look for a substring at the end of a string (Unicode)
71 */
72 public function testEndsWithSpecialChars()
73 {
74 $this->assertTrue(endsWith('å!ùµ', 'ùµ', false));
75 $this->assertTrue(endsWith('µ$åù', 'åù', true));
76 }
77}
78?>
diff --git a/tests/utils/ReferenceLinkDB.php b/tests/utils/ReferenceLinkDB.php
new file mode 100644
index 00000000..2cb05bae
--- /dev/null
+++ b/tests/utils/ReferenceLinkDB.php
@@ -0,0 +1,128 @@
1<?php
2/**
3 * Populates a reference datastore to test LinkDB
4 */
5class ReferenceLinkDB
6{
7 private $links = array();
8 private $publicCount = 0;
9 private $privateCount = 0;
10
11 /**
12 * Populates the test DB with reference data
13 */
14 function __construct()
15 {
16 $this->addLink(
17 'Free as in Freedom 2.0',
18 'https://static.fsf.org/nosvn/faif-2.0.pdf',
19 'Richard Stallman and the Free Software Revolution',
20 0,
21 '20150310_114633',
22 'free gnu software stallman'
23 );
24
25 $this->addLink(
26 'MediaGoblin',
27 'http://mediagoblin.org/',
28 'A free software media publishing platform',
29 0,
30 '20130614_184135',
31 'gnu media web'
32 );
33
34 $this->addLink(
35 'w3c-markup-validator',
36 'https://dvcs.w3.org/hg/markup-validator/summary',
37 'Mercurial repository for the W3C Validator',
38 1,
39 '20141125_084734',
40 'css html w3c web Mercurial'
41 );
42
43 $this->addLink(
44 'UserFriendly - Web Designer',
45 'http://ars.userfriendly.org/cartoons/?id=20121206',
46 'Naming conventions...',
47 0,
48 '20121206_142300',
49 'dev cartoon web'
50 );
51
52 $this->addLink(
53 'UserFriendly - Samba',
54 'http://ars.userfriendly.org/cartoons/?id=20010306',
55 'Tropical printing',
56 0,
57 '20121206_172539',
58 'samba cartoon web'
59 );
60
61 $this->addLink(
62 'Geek and Poke',
63 'http://geek-and-poke.com/',
64 '',
65 1,
66 '20121206_182539',
67 'dev cartoon'
68 );
69 }
70
71 /**
72 * Adds a new link
73 */
74 protected function addLink($title, $url, $description, $private, $date, $tags)
75 {
76 $link = array(
77 'title' => $title,
78 'url' => $url,
79 'description' => $description,
80 'private' => $private,
81 'linkdate' => $date,
82 'tags' => $tags,
83 );
84 $this->links[$date] = $link;
85
86 if ($private) {
87 $this->privateCount++;
88 return;
89 }
90 $this->publicCount++;
91 }
92
93 /**
94 * Writes data to the datastore
95 */
96 public function write($filename, $prefix, $suffix)
97 {
98 file_put_contents(
99 $filename,
100 $prefix.base64_encode(gzdeflate(serialize($this->links))).$suffix
101 );
102 }
103
104 /**
105 * Returns the number of links in the reference data
106 */
107 public function countLinks()
108 {
109 return $this->publicCount + $this->privateCount;
110 }
111
112 /**
113 * Returns the number of public links in the reference data
114 */
115 public function countPublicLinks()
116 {
117 return $this->publicCount;
118 }
119
120 /**
121 * Returns the number of private links in the reference data
122 */
123 public function countPrivateLinks()
124 {
125 return $this->privateCount;
126 }
127}
128?>