3 require_once 'application/NetscapeBookmarkUtils.php';
5 use Shaarli\Config\ConfigManager
;
8 * Utility function to load a file's metadata in a $_FILES-like array
10 * @param string $filename Basename of the file
12 * @return array A $_FILES-like array
14 function file2array($filename)
17 'filetoupload' => array(
19 'tmp_name' => __DIR__
. '/input/' . $filename,
20 'size' => filesize(__DIR__
. '/input/' . $filename)
27 * Netscape bookmark import
29 class BookmarkImportTest
extends PHPUnit_Framework_TestCase
32 * @var string datastore to test write operations
34 protected static $testDatastore = 'sandbox/datastore.php';
37 * @var string History file path
39 protected static $historyFilePath = 'sandbox/history.php';
42 * @var LinkDB private LinkDB instance
44 protected $linkDb = null;
47 * @var string Dummy page cache
49 protected $pagecache = 'tests';
52 * @var ConfigManager instance.
57 * @var History instance.
62 * @var string Save the current timezone.
64 protected static $defaultTimeZone;
66 public static function setUpBeforeClass()
68 self
::$defaultTimeZone = date_default_timezone_get();
69 // Timezone without DST for test consistency
70 date_default_timezone_set('Africa/Nairobi');
74 * Resets test data before each test
76 protected function setUp()
78 if (file_exists(self
::$testDatastore)) {
79 unlink(self
::$testDatastore);
81 // start with an empty datastore
82 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
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);
90 * Delete history file.
92 public function tearDown()
94 @unlink(self
::$historyFilePath);
97 public static function tearDownAfterClass()
99 date_default_timezone_set(self
::$defaultTimeZone);
103 * Attempt to import bookmarks from an empty file
105 public function testImportEmptyData()
107 $files = file2array('empty.htm');
109 'File empty.htm (0 bytes) has an unknown file format.'
110 .' Nothing was imported.',
111 NetscapeBookmarkUtils
::import(null, $files, null, $this->conf
, $this->history
)
113 $this->assertEquals(0, count($this->linkDb
));
117 * Attempt to import bookmarks from a file with no Doctype
119 public function testImportNoDoctype()
121 $files = file2array('no_doctype.htm');
123 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.',
124 NetscapeBookmarkUtils
::import(null, $files, null, $this->conf
, $this->history
)
126 $this->assertEquals(0, count($this->linkDb
));
130 * Attempt to import bookmarks from a file with a lowercase Doctype
132 public function testImportLowecaseDoctype()
134 $files = file2array('lowercase_doctype.htm');
135 $this->assertStringMatchesFormat(
136 'File lowercase_doctype.htm (386 bytes) was successfully processed in %d seconds:'
137 .' 2 links imported, 0 links overwritten, 0 links skipped.',
138 NetscapeBookmarkUtils
::import(null, $files, $this->linkDb
, $this->conf
, $this->history
)
140 $this->assertEquals(2, count($this->linkDb
));
145 * Ensure IE dumps are supported
147 public function testImportInternetExplorerEncoding()
149 $files = file2array('internet_explorer_encoding.htm');
150 $this->assertStringMatchesFormat(
151 'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:'
152 .' 1 links imported, 0 links overwritten, 0 links skipped.',
153 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
155 $this->assertEquals(1, count($this->linkDb
));
156 $this->assertEquals(0, count_private($this->linkDb
));
161 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160618_203944'),
162 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky',
163 'url' => 'http://hginit.com/',
167 'shorturl' => 'La37cg',
169 $this->linkDb
->getLinkFromUrl('http://hginit.com/')
174 * Import bookmarks nested in a folder hierarchy
176 public function testImportNested()
178 $files = file2array('netscape_nested.htm');
179 $this->assertStringMatchesFormat(
180 'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:'
181 .' 8 links imported, 0 links overwritten, 0 links skipped.',
182 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
184 $this->assertEquals(8, count($this->linkDb
));
185 $this->assertEquals(2, count_private($this->linkDb
));
190 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235541'),
191 'title' => 'Nested 1',
192 'url' => 'http://nest.ed/1',
195 'tags' => 'tag1 tag2',
196 'shorturl' => 'KyDNKA',
198 $this->linkDb
->getLinkFromUrl('http://nest.ed/1')
203 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235542'),
204 'title' => 'Nested 1-1',
205 'url' => 'http://nest.ed/1-1',
208 'tags' => 'folder1 tag1 tag2',
209 'shorturl' => 'T2LnXg',
211 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-1')
216 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235547'),
217 'title' => 'Nested 1-2',
218 'url' => 'http://nest.ed/1-2',
221 'tags' => 'folder1 tag3 tag4',
222 'shorturl' => '46SZxA',
224 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-2')
229 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
230 'title' => 'Nested 2-1',
231 'url' => 'http://nest.ed/2-1',
232 'description' => 'First link of the second section',
235 'shorturl' => '4UHOSw',
237 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-1')
242 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
243 'title' => 'Nested 2-2',
244 'url' => 'http://nest.ed/2-2',
245 'description' => 'Second link of the second section',
248 'shorturl' => 'yfzwbw',
250 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-2')
255 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
256 'title' => 'Nested 3-1',
257 'url' => 'http://nest.ed/3-1',
260 'tags' => 'folder3 folder3-1 tag3',
261 'shorturl' => 'UwxIUQ',
263 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-1')
268 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
269 'title' => 'Nested 3-2',
270 'url' => 'http://nest.ed/3-2',
273 'tags' => 'folder3 folder3-1',
274 'shorturl' => 'p8dyZg',
276 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-2')
281 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160229_111541'),
282 'title' => 'Nested 2',
283 'url' => 'http://nest.ed/2',
287 'shorturl' => 'Gt3Uug',
289 $this->linkDb
->getLinkFromUrl('http://nest.ed/2')
294 * Import bookmarks with the default privacy setting (reuse from file)
296 * The $_POST array is not set.
298 public function testImportDefaultPrivacyNoPost()
300 $files = file2array('netscape_basic.htm');
301 $this->assertStringMatchesFormat(
302 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
303 .' 2 links imported, 0 links overwritten, 0 links skipped.',
304 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
307 $this->assertEquals(2, count($this->linkDb
));
308 $this->assertEquals(1, count_private($this->linkDb
));
313 // Old link - UTC+4 (note that TZ in the import file is ignored).
314 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20001010_135536'),
315 'title' => 'Secret stuff',
316 'url' => 'https://private.tld',
317 'description' => "Super-secret stuff you're not supposed to know about",
319 'tags' => 'private secret',
320 'shorturl' => 'EokDtA',
322 $this->linkDb
->getLinkFromUrl('https://private.tld')
327 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235548'),
328 'title' => 'Public stuff',
329 'url' => 'http://public.tld',
332 'tags' => 'public hello world',
333 'shorturl' => 'Er9ddA',
335 $this->linkDb
->getLinkFromUrl('http://public.tld')
340 * Import bookmarks with the default privacy setting (reuse from file)
342 public function testImportKeepPrivacy()
344 $post = array('privacy' => 'default');
345 $files = file2array('netscape_basic.htm');
346 $this->assertStringMatchesFormat(
347 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
348 .' 2 links imported, 0 links overwritten, 0 links skipped.',
349 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
351 $this->assertEquals(2, count($this->linkDb
));
352 $this->assertEquals(1, count_private($this->linkDb
));
357 // Note that TZ in the import file is ignored.
358 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20001010_135536'),
359 'title' => 'Secret stuff',
360 'url' => 'https://private.tld',
361 'description' => "Super-secret stuff you're not supposed to know about",
363 'tags' => 'private secret',
364 'shorturl' => 'EokDtA',
366 $this->linkDb
->getLinkFromUrl('https://private.tld')
371 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235548'),
372 'title' => 'Public stuff',
373 'url' => 'http://public.tld',
376 'tags' => 'public hello world',
377 'shorturl' => 'Er9ddA',
379 $this->linkDb
->getLinkFromUrl('http://public.tld')
384 * Import links as public
386 public function testImportAsPublic()
388 $post = array('privacy' => 'public');
389 $files = file2array('netscape_basic.htm');
390 $this->assertStringMatchesFormat(
391 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
392 .' 2 links imported, 0 links overwritten, 0 links skipped.',
393 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
395 $this->assertEquals(2, count($this->linkDb
));
396 $this->assertEquals(0, count_private($this->linkDb
));
399 $this->linkDb
[0]['private']
403 $this->linkDb
[1]['private']
408 * Import links as private
410 public function testImportAsPrivate()
412 $post = array('privacy' => 'private');
413 $files = file2array('netscape_basic.htm');
414 $this->assertStringMatchesFormat(
415 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
416 .' 2 links imported, 0 links overwritten, 0 links skipped.',
417 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
419 $this->assertEquals(2, count($this->linkDb
));
420 $this->assertEquals(2, count_private($this->linkDb
));
423 $this->linkDb
['0']['private']
427 $this->linkDb
['1']['private']
432 * Overwrite private links so they become public
434 public function testOverwriteAsPublic()
436 $files = file2array('netscape_basic.htm');
438 // import links as private
439 $post = array('privacy' => 'private');
440 $this->assertStringMatchesFormat(
441 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
442 .' 2 links imported, 0 links overwritten, 0 links skipped.',
443 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
445 $this->assertEquals(2, count($this->linkDb
));
446 $this->assertEquals(2, count_private($this->linkDb
));
449 $this->linkDb
[0]['private']
453 $this->linkDb
[1]['private']
455 // re-import as public, enable overwriting
457 'privacy' => 'public',
458 'overwrite' => 'true'
460 $this->assertStringMatchesFormat(
461 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
462 .' 2 links imported, 2 links overwritten, 0 links skipped.',
463 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
465 $this->assertEquals(2, count($this->linkDb
));
466 $this->assertEquals(0, count_private($this->linkDb
));
469 $this->linkDb
[0]['private']
473 $this->linkDb
[1]['private']
478 * Overwrite public links so they become private
480 public function testOverwriteAsPrivate()
482 $files = file2array('netscape_basic.htm');
484 // import links as public
485 $post = array('privacy' => 'public');
486 $this->assertStringMatchesFormat(
487 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
488 .' 2 links imported, 0 links overwritten, 0 links skipped.',
489 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
491 $this->assertEquals(2, count($this->linkDb
));
492 $this->assertEquals(0, count_private($this->linkDb
));
495 $this->linkDb
['0']['private']
499 $this->linkDb
['1']['private']
502 // re-import as private, enable overwriting
504 'privacy' => 'private',
505 'overwrite' => 'true'
507 $this->assertStringMatchesFormat(
508 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
509 .' 2 links imported, 2 links overwritten, 0 links skipped.',
510 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
512 $this->assertEquals(2, count($this->linkDb
));
513 $this->assertEquals(2, count_private($this->linkDb
));
516 $this->linkDb
['0']['private']
520 $this->linkDb
['1']['private']
525 * Attept to import the same links twice without enabling overwriting
527 public function testSkipOverwrite()
529 $post = array('privacy' => 'public');
530 $files = file2array('netscape_basic.htm');
531 $this->assertStringMatchesFormat(
532 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
533 .' 2 links imported, 0 links overwritten, 0 links skipped.',
534 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
536 $this->assertEquals(2, count($this->linkDb
));
537 $this->assertEquals(0, count_private($this->linkDb
));
539 // re-import as private, DO NOT enable overwriting
540 $post = array('privacy' => 'private');
541 $this->assertStringMatchesFormat(
542 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
543 .' 0 links imported, 0 links overwritten, 2 links skipped.',
544 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
546 $this->assertEquals(2, count($this->linkDb
));
547 $this->assertEquals(0, count_private($this->linkDb
));
551 * Add user-specified tags to all imported bookmarks
553 public function testSetDefaultTags()
556 'privacy' => 'public',
557 'default_tags' => 'tag1,tag2 tag3'
559 $files = file2array('netscape_basic.htm');
560 $this->assertStringMatchesFormat(
561 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
562 .' 2 links imported, 0 links overwritten, 0 links skipped.',
563 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
565 $this->assertEquals(2, count($this->linkDb
));
566 $this->assertEquals(0, count_private($this->linkDb
));
568 'tag1 tag2 tag3 private secret',
569 $this->linkDb
['0']['tags']
572 'tag1 tag2 tag3 public hello world',
573 $this->linkDb
['1']['tags']
578 * The user-specified tags contain characters to be escaped
580 public function testSanitizeDefaultTags()
583 'privacy' => 'public',
584 'default_tags' => 'tag1&,tag2 "tag3"'
586 $files = file2array('netscape_basic.htm');
587 $this->assertStringMatchesFormat(
588 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
589 .' 2 links imported, 0 links overwritten, 0 links skipped.',
590 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
592 $this->assertEquals(2, count($this->linkDb
));
593 $this->assertEquals(0, count_private($this->linkDb
));
595 'tag1& tag2 "tag3" private secret',
596 $this->linkDb
['0']['tags']
599 'tag1& tag2 "tag3" public hello world',
600 $this->linkDb
['1']['tags']
605 * Ensure each imported bookmark has a unique id
607 * See https://github.com/shaarli/Shaarli/issues/351
609 public function testImportSameDate()
611 $files = file2array('same_date.htm');
612 $this->assertStringMatchesFormat(
613 'File same_date.htm (453 bytes) was successfully processed in %d seconds:'
614 .' 3 links imported, 0 links overwritten, 0 links skipped.',
615 NetscapeBookmarkUtils
::import(array(), $files, $this->linkDb
, $this->conf
, $this->history
)
617 $this->assertEquals(3, count($this->linkDb
));
618 $this->assertEquals(0, count_private($this->linkDb
));
621 $this->linkDb
[0]['id']
625 $this->linkDb
[1]['id']
629 $this->linkDb
[2]['id']
633 public function testImportCreateUpdateHistory()
636 'privacy' => 'public',
637 'overwrite' => 'true',
639 $files = file2array('netscape_basic.htm');
640 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
);
641 $history = $this->history
->getHistory();
642 $this->assertEquals(1, count($history));
643 $this->assertEquals(History
::IMPORT
, $history[0]['event']);
644 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
646 // re-import as private, enable overwriting
647 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
);
648 $history = $this->history
->getHistory();
649 $this->assertEquals(2, count($history));
650 $this->assertEquals(History
::IMPORT
, $history[0]['event']);
651 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
652 $this->assertEquals(History
::IMPORT
, $history[1]['event']);
653 $this->assertTrue(new DateTime('-5 seconds') < $history[1]['datetime']);