3 require_once 'application/NetscapeBookmarkUtils.php';
7 * Utility function to load a file's metadata in a $_FILES-like array
9 * @param string $filename Basename of the file
11 * @return array A $_FILES-like array
13 function file2array($filename)
16 'filetoupload' => array(
18 'tmp_name' => __DIR__
. '/input/' . $filename,
19 'size' => filesize(__DIR__
. '/input/' . $filename)
26 * Netscape bookmark import
28 class BookmarkImportTest
extends PHPUnit_Framework_TestCase
31 * @var string datastore to test write operations
33 protected static $testDatastore = 'sandbox/datastore.php';
36 * @var LinkDB private LinkDB instance
38 protected $linkDb = null;
41 * @var string Dummy page cache
43 protected $pagecache = 'tests';
46 * @var string Save the current timezone.
48 protected static $defaultTimeZone;
50 public static function setUpBeforeClass()
52 self
::$defaultTimeZone = date_default_timezone_get();
53 // Timezone without DST for test consistency
54 date_default_timezone_set('Africa/Nairobi');
58 * Resets test data before each test
60 protected function setUp()
62 if (file_exists(self
::$testDatastore)) {
63 unlink(self
::$testDatastore);
65 // start with an empty datastore
66 file_put_contents(self
::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
67 $this->linkDb
= new LinkDB(self
::$testDatastore, true, false);
70 public static function tearDownAfterClass()
72 date_default_timezone_set(self
::$defaultTimeZone);
76 * Attempt to import bookmarks from an empty file
78 public function testImportEmptyData()
80 $files = file2array('empty.htm');
82 'File empty.htm (0 bytes) has an unknown file format.'
83 .' Nothing was imported.',
84 NetscapeBookmarkUtils
::import(NULL, $files, NULL, NULL)
86 $this->assertEquals(0, count($this->linkDb
));
90 * Attempt to import bookmarks from a file with no Doctype
92 public function testImportNoDoctype()
94 $files = file2array('no_doctype.htm');
96 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.',
97 NetscapeBookmarkUtils
::import(NULL, $files, NULL, NULL)
99 $this->assertEquals(0, count($this->linkDb
));
103 * Ensure IE dumps are supported
105 public function testImportInternetExplorerEncoding()
107 $files = file2array('internet_explorer_encoding.htm');
109 'File internet_explorer_encoding.htm (356 bytes) was successfully processed:'
110 .' 1 links imported, 0 links overwritten, 0 links skipped.',
111 NetscapeBookmarkUtils
::import(array(), $files, $this->linkDb
, $this->pagecache
)
113 $this->assertEquals(1, count($this->linkDb
));
114 $this->assertEquals(0, count_private($this->linkDb
));
119 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160618_203944'),
120 'title' => 'Hg Init a Mercurial tutorial by Joel Spolsky',
121 'url' => 'http://hginit.com/',
125 'shorturl' => 'La37cg',
127 $this->linkDb
->getLinkFromUrl('http://hginit.com/')
132 * Import bookmarks nested in a folder hierarchy
134 public function testImportNested()
136 $files = file2array('netscape_nested.htm');
138 'File netscape_nested.htm (1337 bytes) was successfully processed:'
139 .' 8 links imported, 0 links overwritten, 0 links skipped.',
140 NetscapeBookmarkUtils
::import(array(), $files, $this->linkDb
, $this->pagecache
)
142 $this->assertEquals(8, count($this->linkDb
));
143 $this->assertEquals(2, count_private($this->linkDb
));
148 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235541'),
149 'title' => 'Nested 1',
150 'url' => 'http://nest.ed/1',
153 'tags' => 'tag1 tag2',
154 'shorturl' => 'KyDNKA',
156 $this->linkDb
->getLinkFromUrl('http://nest.ed/1')
161 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235542'),
162 'title' => 'Nested 1-1',
163 'url' => 'http://nest.ed/1-1',
166 'tags' => 'folder1 tag1 tag2',
167 'shorturl' => 'T2LnXg',
169 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-1')
174 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235547'),
175 'title' => 'Nested 1-2',
176 'url' => 'http://nest.ed/1-2',
179 'tags' => 'folder1 tag3 tag4',
180 'shorturl' => '46SZxA',
182 $this->linkDb
->getLinkFromUrl('http://nest.ed/1-2')
187 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
188 'title' => 'Nested 2-1',
189 'url' => 'http://nest.ed/2-1',
190 'description' => 'First link of the second section',
193 'shorturl' => '4UHOSw',
195 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-1')
200 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
201 'title' => 'Nested 2-2',
202 'url' => 'http://nest.ed/2-2',
203 'description' => 'Second link of the second section',
206 'shorturl' => 'yfzwbw',
208 $this->linkDb
->getLinkFromUrl('http://nest.ed/2-2')
213 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160202_202222'),
214 'title' => 'Nested 3-1',
215 'url' => 'http://nest.ed/3-1',
218 'tags' => 'folder3 folder3-1 tag3',
219 'shorturl' => 'UwxIUQ',
221 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-1')
226 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160119_230227'),
227 'title' => 'Nested 3-2',
228 'url' => 'http://nest.ed/3-2',
231 'tags' => 'folder3 folder3-1',
232 'shorturl' => 'p8dyZg',
234 $this->linkDb
->getLinkFromUrl('http://nest.ed/3-2')
239 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160229_111541'),
240 'title' => 'Nested 2',
241 'url' => 'http://nest.ed/2',
245 'shorturl' => 'Gt3Uug',
247 $this->linkDb
->getLinkFromUrl('http://nest.ed/2')
252 * Import bookmarks with the default privacy setting (reuse from file)
254 * The $_POST array is not set.
256 public function testImportDefaultPrivacyNoPost()
258 $files = file2array('netscape_basic.htm');
260 'File netscape_basic.htm (482 bytes) was successfully processed:'
261 .' 2 links imported, 0 links overwritten, 0 links skipped.',
262 NetscapeBookmarkUtils
::import(array(), $files, $this->linkDb
, $this->pagecache
)
265 $this->assertEquals(2, count($this->linkDb
));
266 $this->assertEquals(1, count_private($this->linkDb
));
271 // Old link - UTC+4 (note that TZ in the import file is ignored).
272 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20001010_135536'),
273 'title' => 'Secret stuff',
274 'url' => 'https://private.tld',
275 'description' => "Super-secret stuff you're not supposed to know about",
277 'tags' => 'private secret',
278 'shorturl' => 'EokDtA',
280 $this->linkDb
->getLinkFromUrl('https://private.tld')
285 'created' => DateTime
::createFromFormat(LinkDB
::LINK_DATE_FORMAT
, '20160225_235548'),
286 'title' => 'Public stuff',
287 'url' => 'http://public.tld',
290 'tags' => 'public hello world',
291 'shorturl' => 'Er9ddA',
293 $this->linkDb
->getLinkFromUrl('http://public.tld')
298 * Import bookmarks with the default privacy setting (reuse from file)
300 public function testImportKeepPrivacy()
302 $post = array('privacy' => 'default');
303 $files = file2array('netscape_basic.htm');
305 'File netscape_basic.htm (482 bytes) was successfully processed:'
306 .' 2 links imported, 0 links overwritten, 0 links skipped.',
307 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
309 $this->assertEquals(2, count($this->linkDb
));
310 $this->assertEquals(1, count_private($this->linkDb
));
315 // 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 links as public
344 public function testImportAsPublic()
346 $post = array('privacy' => 'public');
347 $files = file2array('netscape_basic.htm');
349 'File netscape_basic.htm (482 bytes) was successfully processed:'
350 .' 2 links imported, 0 links overwritten, 0 links skipped.',
351 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
353 $this->assertEquals(2, count($this->linkDb
));
354 $this->assertEquals(0, count_private($this->linkDb
));
357 $this->linkDb
[0]['private']
361 $this->linkDb
[1]['private']
366 * Import links as private
368 public function testImportAsPrivate()
370 $post = array('privacy' => 'private');
371 $files = file2array('netscape_basic.htm');
373 'File netscape_basic.htm (482 bytes) was successfully processed:'
374 .' 2 links imported, 0 links overwritten, 0 links skipped.',
375 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
377 $this->assertEquals(2, count($this->linkDb
));
378 $this->assertEquals(2, count_private($this->linkDb
));
381 $this->linkDb
['0']['private']
385 $this->linkDb
['1']['private']
390 * Overwrite private links so they become public
392 public function testOverwriteAsPublic()
394 $files = file2array('netscape_basic.htm');
396 // import links as private
397 $post = array('privacy' => 'private');
399 'File netscape_basic.htm (482 bytes) was successfully processed:'
400 .' 2 links imported, 0 links overwritten, 0 links skipped.',
401 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
403 $this->assertEquals(2, count($this->linkDb
));
404 $this->assertEquals(2, count_private($this->linkDb
));
407 $this->linkDb
[0]['private']
411 $this->linkDb
[1]['private']
413 // re-import as public, enable overwriting
415 'privacy' => 'public',
416 'overwrite' => 'true'
419 'File netscape_basic.htm (482 bytes) was successfully processed:'
420 .' 2 links imported, 2 links overwritten, 0 links skipped.',
421 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
423 $this->assertEquals(2, count($this->linkDb
));
424 $this->assertEquals(0, count_private($this->linkDb
));
427 $this->linkDb
[0]['private']
431 $this->linkDb
[1]['private']
436 * Overwrite public links so they become private
438 public function testOverwriteAsPrivate()
440 $files = file2array('netscape_basic.htm');
442 // import links as public
443 $post = array('privacy' => 'public');
445 'File netscape_basic.htm (482 bytes) was successfully processed:'
446 .' 2 links imported, 0 links overwritten, 0 links skipped.',
447 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
449 $this->assertEquals(2, count($this->linkDb
));
450 $this->assertEquals(0, count_private($this->linkDb
));
453 $this->linkDb
['0']['private']
457 $this->linkDb
['1']['private']
460 // re-import as private, enable overwriting
462 'privacy' => 'private',
463 'overwrite' => 'true'
466 'File netscape_basic.htm (482 bytes) was successfully processed:'
467 .' 2 links imported, 2 links overwritten, 0 links skipped.',
468 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
470 $this->assertEquals(2, count($this->linkDb
));
471 $this->assertEquals(2, count_private($this->linkDb
));
474 $this->linkDb
['0']['private']
478 $this->linkDb
['1']['private']
483 * Attept to import the same links twice without enabling overwriting
485 public function testSkipOverwrite()
487 $post = array('privacy' => 'public');
488 $files = file2array('netscape_basic.htm');
490 'File netscape_basic.htm (482 bytes) was successfully processed:'
491 .' 2 links imported, 0 links overwritten, 0 links skipped.',
492 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
494 $this->assertEquals(2, count($this->linkDb
));
495 $this->assertEquals(0, count_private($this->linkDb
));
497 // re-import as private, DO NOT enable overwriting
498 $post = array('privacy' => 'private');
500 'File netscape_basic.htm (482 bytes) was successfully processed:'
501 .' 0 links imported, 0 links overwritten, 2 links skipped.',
502 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
504 $this->assertEquals(2, count($this->linkDb
));
505 $this->assertEquals(0, count_private($this->linkDb
));
509 * Add user-specified tags to all imported bookmarks
511 public function testSetDefaultTags()
514 'privacy' => 'public',
515 'default_tags' => 'tag1,tag2 tag3'
517 $files = file2array('netscape_basic.htm');
519 'File netscape_basic.htm (482 bytes) was successfully processed:'
520 .' 2 links imported, 0 links overwritten, 0 links skipped.',
521 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
523 $this->assertEquals(2, count($this->linkDb
));
524 $this->assertEquals(0, count_private($this->linkDb
));
526 'tag1 tag2 tag3 private secret',
527 $this->linkDb
['0']['tags']
530 'tag1 tag2 tag3 public hello world',
531 $this->linkDb
['1']['tags']
536 * The user-specified tags contain characters to be escaped
538 public function testSanitizeDefaultTags()
541 'privacy' => 'public',
542 'default_tags' => 'tag1&,tag2 "tag3"'
544 $files = file2array('netscape_basic.htm');
546 'File netscape_basic.htm (482 bytes) was successfully processed:'
547 .' 2 links imported, 0 links overwritten, 0 links skipped.',
548 NetscapeBookmarkUtils
::import($post, $files, $this->linkDb
, $this->pagecache
)
550 $this->assertEquals(2, count($this->linkDb
));
551 $this->assertEquals(0, count_private($this->linkDb
));
553 'tag1& tag2 "tag3" private secret',
554 $this->linkDb
['0']['tags']
557 'tag1& tag2 "tag3" public hello world',
558 $this->linkDb
['1']['tags']
563 * Ensure each imported bookmark has a unique id
565 * See https://github.com/shaarli/Shaarli/issues/351
567 public function testImportSameDate()
569 $files = file2array('same_date.htm');
571 'File same_date.htm (453 bytes) was successfully processed:'
572 .' 3 links imported, 0 links overwritten, 0 links skipped.',
573 NetscapeBookmarkUtils
::import(array(), $files, $this->linkDb
, $this->pagecache
)
575 $this->assertEquals(3, count($this->linkDb
));
576 $this->assertEquals(0, count_private($this->linkDb
));
579 $this->linkDb
[0]['id']
583 $this->linkDb
[1]['id']
587 $this->linkDb
[2]['id']