3 require_once 'application/NetscapeBookmarkUtils.php';
5 use Shaarli\Config\ConfigManager
;
9 * Utility function to load a file's metadata in a $_FILES-like array
11 * @param string $filename Basename of the file
13 * @return array A $_FILES-like array
15 function file2array($filename)
18 'filetoupload' => array(
20 'tmp_name' => __DIR__
. '/input/' . $filename,
21 'size' => filesize(__DIR__
. '/input/' . $filename)
28 * Netscape bookmark import
30 class BookmarkImportTest
extends PHPUnit_Framework_TestCase
33 * @var string datastore to test write operations
35 protected static $testDatastore = 'sandbox/datastore.php';
38 * @var string History file path
40 protected static $historyFilePath = 'sandbox/history.php';
43 * @var LinkDB private LinkDB instance
45 protected $linkDb = null;
48 * @var string Dummy page cache
50 protected $pagecache = 'tests';
53 * @var ConfigManager instance.
58 * @var History instance.
63 * @var string Save the current timezone.
65 protected static $defaultTimeZone;
67 public static function setUpBeforeClass()
69 self
::$defaultTimeZone = date_default_timezone_get();
70 // Timezone without DST for test consistency
71 date_default_timezone_set('Africa/Nairobi');
75 * Resets test data before each test
77 protected function setUp()
79 if (file_exists(self
::$testDatastore)) {
80 unlink(self
::$testDatastore);
82 // start with an empty datastore
83 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
84 $this->linkDb
= new LinkDB(self
::$testDatastore, true, false);
85 $this->conf
= new ConfigManager('tests/utils/config/configJson');
86 $this->conf
->set('resource.page_cache', $this->pagecache
);
87 $this->history
= new History(self
::$historyFilePath);
91 * Delete history file.
93 public function tearDown()
95 @unlink(self
::$historyFilePath);
98 public static function tearDownAfterClass()
100 date_default_timezone_set(self
::$defaultTimeZone);
104 * Attempt to import bookmarks from an empty file
106 public function testImportEmptyData()
108 $files = file2array('empty.htm');
110 'File empty.htm (0 bytes) has an unknown file format.'
111 .' Nothing was imported.',
112 NetscapeBookmarkUtils
::import(null, $files, null, $this->conf
, $this->history
)
114 $this->assertEquals(0, count($this->linkDb
));
118 * Attempt to import bookmarks from a file with no Doctype
120 public function testImportNoDoctype()
122 $files = file2array('no_doctype.htm');
124 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.',
125 NetscapeBookmarkUtils
::import(null, $files, null, $this->conf
, $this->history
)
127 $this->assertEquals(0, count($this->linkDb
));
131 * Attempt to import bookmarks from a file with a lowercase Doctype
133 public function testImportLowecaseDoctype()
135 $files = file2array('lowercase_doctype.htm');
136 $this->assertStringMatchesFormat(
137 'File lowercase_doctype.htm (386 bytes) was successfully processed in %d seconds:'
138 .' 2 links imported, 0 links overwritten, 0 links skipped.',
139 NetscapeBookmarkUtils
::import(null, $files, $this->linkDb
, $this->conf
, $this->history
)
141 $this->assertEquals(2, count($this->linkDb
));
146 * Ensure IE dumps are supported
148 public function testImportInternetExplorerEncoding()
150 $files = file2array('internet_explorer_encoding.htm');
151 $this->assertStringMatchesFormat(
152 'File internet_explorer_encoding.htm (356 bytes) was successfully processed in %d seconds:'
153 .' 1 links imported, 0 links overwritten, 0 links skipped.',
154 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
156 $this->assertEquals(1, count($this->linkDb
));
157 $this->assertEquals(0, count_private($this->linkDb
));
162 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160618_203944'),
163 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky',
164 'url' => 'http://hginit.com/',
168 'shorturl' => 'La37cg',
170 $this->linkDb
->getLinkFromUrl('http://hginit.com/')
175 * Import bookmarks nested in a folder hierarchy
177 public function testImportNested()
179 $files = file2array('netscape_nested.htm');
180 $this->assertStringMatchesFormat(
181 'File netscape_nested.htm (1337 bytes) was successfully processed in %d seconds:'
182 .' 8 links imported, 0 links overwritten, 0 links skipped.',
183 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
185 $this->assertEquals(8, count($this->linkDb
));
186 $this->assertEquals(2, count_private($this->linkDb
));
191 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235541'),
192 'title' => 'Nested 1',
193 'url' => 'http://nest.ed/1',
196 'tags' => 'tag1 tag2',
197 'shorturl' => 'KyDNKA',
199 $this->linkDb
->getLinkFromUrl('http://nest.ed/1')
204 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235542'),
205 'title' => 'Nested 1-1',
206 'url' => 'http://nest.ed/1-1',
209 'tags' => 'folder1 tag1 tag2',
210 'shorturl' => 'T2LnXg',
212 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-1')
217 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235547'),
218 'title' => 'Nested 1-2',
219 'url' => 'http://nest.ed/1-2',
222 'tags' => 'folder1 tag3 tag4',
223 'shorturl' => '46SZxA',
225 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-2')
230 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
231 'title' => 'Nested 2-1',
232 'url' => 'http://nest.ed/2-1',
233 'description' => 'First link of the second section',
236 'shorturl' => '4UHOSw',
238 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-1')
243 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
244 'title' => 'Nested 2-2',
245 'url' => 'http://nest.ed/2-2',
246 'description' => 'Second link of the second section',
249 'shorturl' => 'yfzwbw',
251 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-2')
256 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
257 'title' => 'Nested 3-1',
258 'url' => 'http://nest.ed/3-1',
261 'tags' => 'folder3 folder3-1 tag3',
262 'shorturl' => 'UwxIUQ',
264 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-1')
269 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
270 'title' => 'Nested 3-2',
271 'url' => 'http://nest.ed/3-2',
274 'tags' => 'folder3 folder3-1',
275 'shorturl' => 'p8dyZg',
277 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-2')
282 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160229_111541'),
283 'title' => 'Nested 2',
284 'url' => 'http://nest.ed/2',
288 'shorturl' => 'Gt3Uug',
290 $this->linkDb
->getLinkFromUrl('http://nest.ed/2')
295 * Import bookmarks with the default privacy setting (reuse from file)
297 * The $_POST array is not set.
299 public function testImportDefaultPrivacyNoPost()
301 $files = file2array('netscape_basic.htm');
302 $this->assertStringMatchesFormat(
303 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
304 .' 2 links imported, 0 links overwritten, 0 links skipped.',
305 NetscapeBookmarkUtils
::import([], $files, $this->linkDb
, $this->conf
, $this->history
)
308 $this->assertEquals(2, count($this->linkDb
));
309 $this->assertEquals(1, count_private($this->linkDb
));
314 // Old link - UTC+4 (note that TZ in the import file is ignored).
315 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20001010_135536'),
316 'title' => 'Secret stuff',
317 'url' => 'https://private.tld',
318 'description' => "Super-secret stuff you're not supposed to know about",
320 'tags' => 'private secret',
321 'shorturl' => 'EokDtA',
323 $this->linkDb
->getLinkFromUrl('https://private.tld')
328 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235548'),
329 'title' => 'Public stuff',
330 'url' => 'http://public.tld',
333 'tags' => 'public hello world',
334 'shorturl' => 'Er9ddA',
336 $this->linkDb
->getLinkFromUrl('http://public.tld')
341 * Import bookmarks with the default privacy setting (reuse from file)
343 public function testImportKeepPrivacy()
345 $post = array('privacy' => 'default');
346 $files = file2array('netscape_basic.htm');
347 $this->assertStringMatchesFormat(
348 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
349 .' 2 links imported, 0 links overwritten, 0 links skipped.',
350 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
352 $this->assertEquals(2, count($this->linkDb
));
353 $this->assertEquals(1, count_private($this->linkDb
));
358 // Note that TZ in the import file is ignored.
359 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20001010_135536'),
360 'title' => 'Secret stuff',
361 'url' => 'https://private.tld',
362 'description' => "Super-secret stuff you're not supposed to know about",
364 'tags' => 'private secret',
365 'shorturl' => 'EokDtA',
367 $this->linkDb
->getLinkFromUrl('https://private.tld')
372 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235548'),
373 'title' => 'Public stuff',
374 'url' => 'http://public.tld',
377 'tags' => 'public hello world',
378 'shorturl' => 'Er9ddA',
380 $this->linkDb
->getLinkFromUrl('http://public.tld')
385 * Import links as public
387 public function testImportAsPublic()
389 $post = array('privacy' => 'public');
390 $files = file2array('netscape_basic.htm');
391 $this->assertStringMatchesFormat(
392 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
393 .' 2 links imported, 0 links overwritten, 0 links skipped.',
394 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
396 $this->assertEquals(2, count($this->linkDb
));
397 $this->assertEquals(0, count_private($this->linkDb
));
400 $this->linkDb
[0]['private']
404 $this->linkDb
[1]['private']
409 * Import links as private
411 public function testImportAsPrivate()
413 $post = array('privacy' => 'private');
414 $files = file2array('netscape_basic.htm');
415 $this->assertStringMatchesFormat(
416 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
417 .' 2 links imported, 0 links overwritten, 0 links skipped.',
418 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
420 $this->assertEquals(2, count($this->linkDb
));
421 $this->assertEquals(2, count_private($this->linkDb
));
424 $this->linkDb
['0']['private']
428 $this->linkDb
['1']['private']
433 * Overwrite private links so they become public
435 public function testOverwriteAsPublic()
437 $files = file2array('netscape_basic.htm');
439 // import links as private
440 $post = array('privacy' => 'private');
441 $this->assertStringMatchesFormat(
442 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
443 .' 2 links imported, 0 links overwritten, 0 links skipped.',
444 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
446 $this->assertEquals(2, count($this->linkDb
));
447 $this->assertEquals(2, count_private($this->linkDb
));
450 $this->linkDb
[0]['private']
454 $this->linkDb
[1]['private']
456 // re-import as public, enable overwriting
458 'privacy' => 'public',
459 'overwrite' => 'true'
461 $this->assertStringMatchesFormat(
462 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
463 .' 2 links imported, 2 links overwritten, 0 links skipped.',
464 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
466 $this->assertEquals(2, count($this->linkDb
));
467 $this->assertEquals(0, count_private($this->linkDb
));
470 $this->linkDb
[0]['private']
474 $this->linkDb
[1]['private']
479 * Overwrite public links so they become private
481 public function testOverwriteAsPrivate()
483 $files = file2array('netscape_basic.htm');
485 // import links as public
486 $post = array('privacy' => 'public');
487 $this->assertStringMatchesFormat(
488 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
489 .' 2 links imported, 0 links overwritten, 0 links skipped.',
490 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
492 $this->assertEquals(2, count($this->linkDb
));
493 $this->assertEquals(0, count_private($this->linkDb
));
496 $this->linkDb
['0']['private']
500 $this->linkDb
['1']['private']
503 // re-import as private, enable overwriting
505 'privacy' => 'private',
506 'overwrite' => 'true'
508 $this->assertStringMatchesFormat(
509 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
510 .' 2 links imported, 2 links overwritten, 0 links skipped.',
511 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
513 $this->assertEquals(2, count($this->linkDb
));
514 $this->assertEquals(2, count_private($this->linkDb
));
517 $this->linkDb
['0']['private']
521 $this->linkDb
['1']['private']
526 * Attept to import the same links twice without enabling overwriting
528 public function testSkipOverwrite()
530 $post = array('privacy' => 'public');
531 $files = file2array('netscape_basic.htm');
532 $this->assertStringMatchesFormat(
533 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
534 .' 2 links imported, 0 links overwritten, 0 links skipped.',
535 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
537 $this->assertEquals(2, count($this->linkDb
));
538 $this->assertEquals(0, count_private($this->linkDb
));
540 // re-import as private, DO NOT enable overwriting
541 $post = array('privacy' => 'private');
542 $this->assertStringMatchesFormat(
543 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
544 .' 0 links imported, 0 links overwritten, 2 links skipped.',
545 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
547 $this->assertEquals(2, count($this->linkDb
));
548 $this->assertEquals(0, count_private($this->linkDb
));
552 * Add user-specified tags to all imported bookmarks
554 public function testSetDefaultTags()
557 'privacy' => 'public',
558 'default_tags' => 'tag1,tag2 tag3'
560 $files = file2array('netscape_basic.htm');
561 $this->assertStringMatchesFormat(
562 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
563 .' 2 links imported, 0 links overwritten, 0 links skipped.',
564 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
566 $this->assertEquals(2, count($this->linkDb
));
567 $this->assertEquals(0, count_private($this->linkDb
));
569 'tag1 tag2 tag3 private secret',
570 $this->linkDb
['0']['tags']
573 'tag1 tag2 tag3 public hello world',
574 $this->linkDb
['1']['tags']
579 * The user-specified tags contain characters to be escaped
581 public function testSanitizeDefaultTags()
584 'privacy' => 'public',
585 'default_tags' => 'tag1&,tag2 "tag3"'
587 $files = file2array('netscape_basic.htm');
588 $this->assertStringMatchesFormat(
589 'File netscape_basic.htm (482 bytes) was successfully processed in %d seconds:'
590 .' 2 links imported, 0 links overwritten, 0 links skipped.',
591 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
)
593 $this->assertEquals(2, count($this->linkDb
));
594 $this->assertEquals(0, count_private($this->linkDb
));
596 'tag1& tag2 "tag3" private secret',
597 $this->linkDb
['0']['tags']
600 'tag1& tag2 "tag3" public hello world',
601 $this->linkDb
['1']['tags']
606 * Ensure each imported bookmark has a unique id
608 * See https://github.com/shaarli/Shaarli/issues/351
610 public function testImportSameDate()
612 $files = file2array('same_date.htm');
613 $this->assertStringMatchesFormat(
614 'File same_date.htm (453 bytes) was successfully processed in %d seconds:'
615 .' 3 links imported, 0 links overwritten, 0 links skipped.',
616 NetscapeBookmarkUtils
::import(array(), $files, $this->linkDb
, $this->conf
, $this->history
)
618 $this->assertEquals(3, count($this->linkDb
));
619 $this->assertEquals(0, count_private($this->linkDb
));
622 $this->linkDb
[0]['id']
626 $this->linkDb
[1]['id']
630 $this->linkDb
[2]['id']
634 public function testImportCreateUpdateHistory()
637 'privacy' => 'public',
638 'overwrite' => 'true',
640 $files = file2array('netscape_basic.htm');
641 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
);
642 $history = $this->history
->getHistory();
643 $this->assertEquals(1, count($history));
644 $this->assertEquals(History
::IMPORT
, $history[0]['event']);
645 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
647 // re-import as private, enable overwriting
648 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->conf
, $this->history
);
649 $history = $this->history
->getHistory();
650 $this->assertEquals(2, count($history));
651 $this->assertEquals(History
::IMPORT
, $history[0]['event']);
652 $this->assertTrue(new DateTime('-5 seconds') < $history[0]['datetime']);
653 $this->assertEquals(History
::IMPORT
, $history[1]['event']);
654 $this->assertTrue(new DateTime('-5 seconds') < $history[1]['datetime']);