2 namespace Shaarli\Netscape
;
5 use Shaarli\Bookmark\LinkDB
;
6 use Shaarli\Config\ConfigManager
;
10 * Utility function to load a file's metadata in a $_FILES-like array
12 * @param string $filename Basename of the file
14 * @return array A $_FILES-like array
16 function file2array($filename)
19 'filetoupload' => array(
21 'tmp_name' => __DIR__
. '/input/' . $filename,
22 'size' => filesize(__DIR__
. '/input/' . $filename)
29 * Netscape bookmark import
31 class BookmarkImportTest
extends \PHPUnit\Framework\TestCase
34 * @var string datastore to test write operations
36 protected static $testDatastore = 'sandbox/datastore.php';
39 * @var string History file path
41 protected static $historyFilePath = 'sandbox/history.php';
44 * @var LinkDB private LinkDB instance
46 protected $linkDb = null;
49 * @var string Dummy page cache
51 protected $pagecache = 'tests';
54 * @var ConfigManager instance.
59 * @var History instance.
64 * @var string Save the current timezone.
66 protected static $defaultTimeZone;
68 public static function setUpBeforeClass()
70 self
::$defaultTimeZone = date_default_timezone_get();
71 // Timezone without DST for test consistency
72 date_default_timezone_set('Africa/Nairobi');
76 * Resets test data before each test
78 protected function setUp()
80 if (file_exists(self
::$testDatastore)) {
81 unlink(self
::$testDatastore);
83 // start with an empty datastore
84 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
85 $this->linkDb
= new LinkDB(self
::$testDatastore, true, false);
86 $this->conf
= new ConfigManager('tests/utils/config/configJson');
87 $this->conf
->set('resource.page_cache', $this->pagecache
);
88 $this->history
= new History(self
::$historyFilePath);
92 * Delete history file.
94 public function tearDown()
96 @unlink(self
::$historyFilePath);
99 public static function tearDownAfterClass()
101 date_default_timezone_set(self
::$defaultTimeZone);
105 * Attempt to import bookmarks from an empty file
107 public function testImportEmptyData()
109 $files = file2array('empty.htm');
111 'File empty.htm (0 bytes) has an unknown file format.'
112 .' Nothing was imported.',
113 NetscapeBookmarkUtils
::import(null, $files, null, $this->conf
, $this->history
)
115 $this->assertEquals(0, count($this->linkDb
));
119 * Attempt to import bookmarks from a file with no Doctype
121 public function testImportNoDoctype()
123 $files = file2array('no_doctype.htm');
125 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.',
126 NetscapeBookmarkUtils
::import(null, $files, null, $this->conf
, $this->history
)
128 $this->assertEquals(0, count($this->linkDb
));
132 * Attempt to import bookmarks from a file with a lowercase Doctype
134 public function testImportLowecaseDoctype()
136 $files = file2array('lowercase_doctype.htm');
137 $this->assertStringMatchesFormat(
138 'File lowercase_doctype.htm (386 bytes) was successfully processed in %d seconds:'
139 .' 2 links imported, 0 links overwritten, 0 links skipped.',
140 NetscapeBookmarkUtils
::import(null, $files, $this->linkDb
, $this->conf
, $this->history
)
142 $this->assertEquals(2, count($this->linkDb
));
147 * Ensure IE dumps are supported
149 public function testImportInternetExplorerEncoding()
151 $files = file2array('internet_explorer_encoding.htm');
152 $this->assertStringMatchesFormat(
153 'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:'
154 .' 1 links imported, 0 links overwritten, 0 links skipped.',
155 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
157 $this->assertEquals(1, count($this->linkDb
));
158 $this->assertEquals(0, count_private($this->linkDb
));
163 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160618_203944'),
164 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky',
165 'url' => 'http://hginit.com/',
169 'shorturl' => 'La37cg',
171 $this->linkDb
->getLinkFromUrl('http://hginit.com/')
176 * Import bookmarks nested in a folder hierarchy
178 public function testImportNested()
180 $files = file2array('netscape_nested.htm');
181 $this->assertStringMatchesFormat(
182 'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:'
183 .' 8 links imported, 0 links overwritten, 0 links skipped.',
184 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
186 $this->assertEquals(8, count($this->linkDb
));
187 $this->assertEquals(2, count_private($this->linkDb
));
192 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235541'),
193 'title' => 'Nested 1',
194 'url' => 'http://nest.ed/1',
197 'tags' => 'tag1 tag2',
198 'shorturl' => 'KyDNKA',
200 $this->linkDb
->getLinkFromUrl('http://nest.ed/1')
205 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235542'),
206 'title' => 'Nested 1-1',
207 'url' => 'http://nest.ed/1-1',
210 'tags' => 'folder1 tag1 tag2',
211 'shorturl' => 'T2LnXg',
213 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-1')
218 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235547'),
219 'title' => 'Nested 1-2',
220 'url' => 'http://nest.ed/1-2',
223 'tags' => 'folder1 tag3 tag4',
224 'shorturl' => '46SZxA',
226 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-2')
231 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
232 'title' => 'Nested 2-1',
233 'url' => 'http://nest.ed/2-1',
234 'description' => 'First link of the second section',
237 'shorturl' => '4UHOSw',
239 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-1')
244 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
245 'title' => 'Nested 2-2',
246 'url' => 'http://nest.ed/2-2',
247 'description' => 'Second link of the second section',
250 'shorturl' => 'yfzwbw',
252 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-2')
257 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
258 'title' => 'Nested 3-1',
259 'url' => 'http://nest.ed/3-1',
262 'tags' => 'folder3 folder3-1 tag3',
263 'shorturl' => 'UwxIUQ',
265 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-1')
270 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
271 'title' => 'Nested 3-2',
272 'url' => 'http://nest.ed/3-2',
275 'tags' => 'folder3 folder3-1',
276 'shorturl' => 'p8dyZg',
278 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-2')
283 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160229_111541'),
284 'title' => 'Nested 2',
285 'url' => 'http://nest.ed/2',
289 'shorturl' => 'Gt3Uug',
291 $this->linkDb
->getLinkFromUrl('http://nest.ed/2')
296 * Import bookmarks with the default privacy setting (reuse from file)
298 * The $_POST array is not set.
300 public function testImportDefaultPrivacyNoPost()
302 $files = file2array('netscape_basic.htm');
303 $this->assertStringMatchesFormat(
304 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
305 .' 2 links imported, 0 links overwritten, 0 links skipped.',
306 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
309 $this->assertEquals(2, count($this->linkDb
));
310 $this->assertEquals(1, count_private($this->linkDb
));
315 // Old link - UTC+4 (note that TZ in the import file is ignored).
316 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20001010_135536'),
317 'title' => 'Secret stuff',
318 'url' => 'https://private.tld',
319 'description' => "Super-secret stuff you're not supposed to know about",
321 'tags' => 'private secret',
322 'shorturl' => 'EokDtA',
324 $this->linkDb
->getLinkFromUrl('https://private.tld')
329 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235548'),
330 'title' => 'Public stuff',
331 'url' => 'http://public.tld',
334 'tags' => 'public hello world',
335 'shorturl' => 'Er9ddA',
337 $this->linkDb
->getLinkFromUrl('http://public.tld')
342 * Import bookmarks with the default privacy setting (reuse from file)
344 public function testImportKeepPrivacy()
346 $post = array('privacy' => 'default');
347 $files = file2array('netscape_basic.htm');
348 $this->assertStringMatchesFormat(
349 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
350 .' 2 links imported, 0 links overwritten, 0 links skipped.',
351 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
353 $this->assertEquals(2, count($this->linkDb
));
354 $this->assertEquals(1, count_private($this->linkDb
));
359 // Note that TZ in the import file is ignored.
360 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20001010_135536'),
361 'title' => 'Secret stuff',
362 'url' => 'https://private.tld',
363 'description' => "Super-secret stuff you're not supposed to know about",
365 'tags' => 'private secret',
366 'shorturl' => 'EokDtA',
368 $this->linkDb
->getLinkFromUrl('https://private.tld')
373 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235548'),
374 'title' => 'Public stuff',
375 'url' => 'http://public.tld',
378 'tags' => 'public hello world',
379 'shorturl' => 'Er9ddA',
381 $this->linkDb
->getLinkFromUrl('http://public.tld')
386 * Import links as public
388 public function testImportAsPublic()
390 $post = array('privacy' => 'public');
391 $files = file2array('netscape_basic.htm');
392 $this->assertStringMatchesFormat(
393 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
394 .' 2 links imported, 0 links overwritten, 0 links skipped.',
395 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
397 $this->assertEquals(2, count($this->linkDb
));
398 $this->assertEquals(0, count_private($this->linkDb
));
401 $this->linkDb
[0]['private']
405 $this->linkDb
[1]['private']
410 * Import links as private
412 public function testImportAsPrivate()
414 $post = array('privacy' => 'private');
415 $files = file2array('netscape_basic.htm');
416 $this->assertStringMatchesFormat(
417 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
418 .' 2 links imported, 0 links overwritten, 0 links skipped.',
419 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
421 $this->assertEquals(2, count($this->linkDb
));
422 $this->assertEquals(2, count_private($this->linkDb
));
425 $this->linkDb
['0']['private']
429 $this->linkDb
['1']['private']
434 * Overwrite private links so they become public
436 public function testOverwriteAsPublic()
438 $files = file2array('netscape_basic.htm');
440 // import links as private
441 $post = array('privacy' => 'private');
442 $this->assertStringMatchesFormat(
443 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
444 .' 2 links imported, 0 links overwritten, 0 links skipped.',
445 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
447 $this->assertEquals(2, count($this->linkDb
));
448 $this->assertEquals(2, count_private($this->linkDb
));
451 $this->linkDb
[0]['private']
455 $this->linkDb
[1]['private']
457 // re-import as public, enable overwriting
459 'privacy' => 'public',
460 'overwrite' => 'true'
462 $this->assertStringMatchesFormat(
463 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
464 .' 2 links imported, 2 links overwritten, 0 links skipped.',
465 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
467 $this->assertEquals(2, count($this->linkDb
));
468 $this->assertEquals(0, count_private($this->linkDb
));
471 $this->linkDb
[0]['private']
475 $this->linkDb
[1]['private']
480 * Overwrite public links so they become private
482 public function testOverwriteAsPrivate()
484 $files = file2array('netscape_basic.htm');
486 // import links as public
487 $post = array('privacy' => 'public');
488 $this->assertStringMatchesFormat(
489 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
490 .' 2 links imported, 0 links overwritten, 0 links skipped.',
491 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
493 $this->assertEquals(2, count($this->linkDb
));
494 $this->assertEquals(0, count_private($this->linkDb
));
497 $this->linkDb
['0']['private']
501 $this->linkDb
['1']['private']
504 // re-import as private, enable overwriting
506 'privacy' => 'private',
507 'overwrite' => 'true'
509 $this->assertStringMatchesFormat(
510 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
511 .' 2 links imported, 2 links overwritten, 0 links skipped.',
512 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
514 $this->assertEquals(2, count($this->linkDb
));
515 $this->assertEquals(2, count_private($this->linkDb
));
518 $this->linkDb
['0']['private']
522 $this->linkDb
['1']['private']
527 * Attept to import the same links twice without enabling overwriting
529 public function testSkipOverwrite()
531 $post = array('privacy' => 'public');
532 $files = file2array('netscape_basic.htm');
533 $this->assertStringMatchesFormat(
534 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
535 .' 2 links imported, 0 links overwritten, 0 links skipped.',
536 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
538 $this->assertEquals(2, count($this->linkDb
));
539 $this->assertEquals(0, count_private($this->linkDb
));
541 // re-import as private, DO NOT enable overwriting
542 $post = array('privacy' => 'private');
543 $this->assertStringMatchesFormat(
544 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
545 .' 0 links imported, 0 links overwritten, 2 links skipped.',
546 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
548 $this->assertEquals(2, count($this->linkDb
));
549 $this->assertEquals(0, count_private($this->linkDb
));
553 * Add user-specified tags to all imported bookmarks
555 public function testSetDefaultTags()
558 'privacy' => 'public',
559 'default_tags' => 'tag1,tag2 tag3'
561 $files = file2array('netscape_basic.htm');
562 $this->assertStringMatchesFormat(
563 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
564 .' 2 links imported, 0 links overwritten, 0 links skipped.',
565 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
567 $this->assertEquals(2, count($this->linkDb
));
568 $this->assertEquals(0, count_private($this->linkDb
));
570 'tag1 tag2 tag3 private secret',
571 $this->linkDb
['0']['tags']
574 'tag1 tag2 tag3 public hello world',
575 $this->linkDb
['1']['tags']
580 * The user-specified tags contain characters to be escaped
582 public function testSanitizeDefaultTags()
585 'privacy' => 'public',
586 'default_tags' => 'tag1&,tag2 "tag3"'
588 $files = file2array('netscape_basic.htm');
589 $this->assertStringMatchesFormat(
590 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
591 .' 2 links imported, 0 links overwritten, 0 links skipped.',
592 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
594 $this->assertEquals(2, count($this->linkDb
));
595 $this->assertEquals(0, count_private($this->linkDb
));
597 'tag1& tag2 "tag3" private secret',
598 $this->linkDb
['0']['tags']
601 'tag1& tag2 "tag3" public hello world',
602 $this->linkDb
['1']['tags']
607 * Ensure each imported bookmark has a unique id
609 * See https://github.com/shaarli/Shaarli/issues/351
611 public function testImportSameDate()
613 $files = file2array('same_date.htm');
614 $this->assertStringMatchesFormat(
615 'File same_date.htm (453 bytes) was successfully processed in %d seconds:'
616 .' 3 links imported, 0 links overwritten, 0 links skipped.',
617 NetscapeBookmarkUtils
::import(array(), $files, $this->linkDb
, $this->conf
, $this->history
)
619 $this->assertEquals(3, count($this->linkDb
));
620 $this->assertEquals(0, count_private($this->linkDb
));
623 $this->linkDb
[0]['id']
627 $this->linkDb
[1]['id']
631 $this->linkDb
[2]['id']
635 public function testImportCreateUpdateHistory()
638 'privacy' => 'public',
639 'overwrite' => 'true',
641 $files = file2array('netscape_basic.htm');
642 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
);
643 $history = $this->history
->getHistory();
644 $this->assertEquals(1, count($history));
645 $this->assertEquals(History
::IMPORT
, $history[0]['event']);
646 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
648 // re-import as private, enable overwriting
649 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
);
650 $history = $this->history
->getHistory();
651 $this->assertEquals(2, count($history));
652 $this->assertEquals(History
::IMPORT
, $history[0]['event']);
653 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
654 $this->assertEquals(History
::IMPORT
, $history[1]['event']);
655 $this->assertTrue(new DateTime('-5 seconds') < $history[1]['datetime']);