aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests/NetscapeBookmarkUtils
diff options
context:
space:
mode:
authorArthur <arthur@hoa.ro>2016-08-10 12:10:41 +0200
committerGitHub <noreply@github.com>2016-08-10 12:10:41 +0200
commite0dd77c37e433d71462f87c8e8c75196aa958940 (patch)
tree4a13ddf32779cb8f02600d7cc20d23f692c9068c /tests/NetscapeBookmarkUtils
parent085157c5cb6bd0df928c7875fb7997683418f1fb (diff)
parenta973afeac7b7399d35b881920f0afc1947765ccd (diff)
downloadShaarli-e0dd77c37e433d71462f87c8e8c75196aa958940.tar.gz
Shaarli-e0dd77c37e433d71462f87c8e8c75196aa958940.tar.zst
Shaarli-e0dd77c37e433d71462f87c8e8c75196aa958940.zip
Merge pull request #612 from virtualtam/refactor/bookmark-parser
Refactor bookmark import using a generic Netscape parser
Diffstat (limited to 'tests/NetscapeBookmarkUtils')
-rw-r--r--tests/NetscapeBookmarkUtils/BookmarkExportTest.php134
-rw-r--r--tests/NetscapeBookmarkUtils/BookmarkImportTest.php518
-rw-r--r--tests/NetscapeBookmarkUtils/input/empty.htm0
-rw-r--r--tests/NetscapeBookmarkUtils/input/netscape_basic.htm11
-rw-r--r--tests/NetscapeBookmarkUtils/input/netscape_nested.htm31
-rw-r--r--tests/NetscapeBookmarkUtils/input/no_doctype.htm7
-rw-r--r--tests/NetscapeBookmarkUtils/input/same_date.htm11
7 files changed, 712 insertions, 0 deletions
diff --git a/tests/NetscapeBookmarkUtils/BookmarkExportTest.php b/tests/NetscapeBookmarkUtils/BookmarkExportTest.php
new file mode 100644
index 00000000..cc54ab9f
--- /dev/null
+++ b/tests/NetscapeBookmarkUtils/BookmarkExportTest.php
@@ -0,0 +1,134 @@
1<?php
2
3require_once 'application/NetscapeBookmarkUtils.php';
4
5/**
6 * Netscape bookmark export
7 */
8class BookmarkExportTest extends PHPUnit_Framework_TestCase
9{
10 /**
11 * @var string datastore to test write operations
12 */
13 protected static $testDatastore = 'sandbox/datastore.php';
14
15 /**
16 * @var ReferenceLinkDB instance.
17 */
18 protected static $refDb = null;
19
20 /**
21 * @var LinkDB private LinkDB instance.
22 */
23 protected static $linkDb = null;
24
25 /**
26 * Instantiate reference data
27 */
28 public static function setUpBeforeClass()
29 {
30 self::$refDb = new ReferenceLinkDB();
31 self::$refDb->write(self::$testDatastore);
32 self::$linkDb = new LinkDB(self::$testDatastore, true, false);
33 }
34
35 /**
36 * Attempt to export an invalid link selection
37 * @expectedException Exception
38 * @expectedExceptionMessageRegExp /Invalid export selection/
39 */
40 public function testFilterAndFormatInvalid()
41 {
42 NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'derp', false, '');
43 }
44
45 /**
46 * Prepare all links for export
47 */
48 public function testFilterAndFormatAll()
49 {
50 $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'all', false, '');
51 $this->assertEquals(self::$refDb->countLinks(), sizeof($links));
52 foreach ($links as $link) {
53 $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']);
54 $this->assertEquals(
55 $date->getTimestamp(),
56 $link['timestamp']
57 );
58 $this->assertEquals(
59 str_replace(' ', ',', $link['tags']),
60 $link['taglist']
61 );
62 }
63 }
64
65 /**
66 * Prepare private links for export
67 */
68 public function testFilterAndFormatPrivate()
69 {
70 $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'private', false, '');
71 $this->assertEquals(self::$refDb->countPrivateLinks(), sizeof($links));
72 foreach ($links as $link) {
73 $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']);
74 $this->assertEquals(
75 $date->getTimestamp(),
76 $link['timestamp']
77 );
78 $this->assertEquals(
79 str_replace(' ', ',', $link['tags']),
80 $link['taglist']
81 );
82 }
83 }
84
85 /**
86 * Prepare public links for export
87 */
88 public function testFilterAndFormatPublic()
89 {
90 $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, '');
91 $this->assertEquals(self::$refDb->countPublicLinks(), sizeof($links));
92 foreach ($links as $link) {
93 $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']);
94 $this->assertEquals(
95 $date->getTimestamp(),
96 $link['timestamp']
97 );
98 $this->assertEquals(
99 str_replace(' ', ',', $link['tags']),
100 $link['taglist']
101 );
102 }
103 }
104
105 /**
106 * Do not prepend notes with the Shaarli index's URL
107 */
108 public function testFilterAndFormatDoNotPrependNoteUrl()
109 {
110 $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, '');
111 $this->assertEquals(
112 '?WDWyig',
113 $links[0]['url']
114 );
115 }
116
117 /**
118 * Prepend notes with the Shaarli index's URL
119 */
120 public function testFilterAndFormatPrependNoteUrl()
121 {
122 $indexUrl = 'http://localhost:7469/shaarli/';
123 $links = NetscapeBookmarkUtils::filterAndFormat(
124 self::$linkDb,
125 'public',
126 true,
127 $indexUrl
128 );
129 $this->assertEquals(
130 $indexUrl . '?WDWyig',
131 $links[0]['url']
132 );
133 }
134}
diff --git a/tests/NetscapeBookmarkUtils/BookmarkImportTest.php b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php
new file mode 100644
index 00000000..2d4e7557
--- /dev/null
+++ b/tests/NetscapeBookmarkUtils/BookmarkImportTest.php
@@ -0,0 +1,518 @@
1<?php
2
3require_once 'application/NetscapeBookmarkUtils.php';
4
5
6/**
7 * Utility function to load a file's metadata in a $_FILES-like array
8 *
9 * @param string $filename Basename of the file
10 *
11 * @return array A $_FILES-like array
12 */
13function file2array($filename)
14{
15 return array(
16 'filetoupload' => array(
17 'name' => $filename,
18 'tmp_name' => __DIR__ . '/input/' . $filename,
19 'size' => filesize(__DIR__ . '/input/' . $filename)
20 )
21 );
22}
23
24
25/**
26 * Netscape bookmark import
27 */
28class BookmarkImportTest extends PHPUnit_Framework_TestCase
29{
30 /**
31 * @var string datastore to test write operations
32 */
33 protected static $testDatastore = 'sandbox/datastore.php';
34
35 /**
36 * @var LinkDB private LinkDB instance
37 */
38 protected $linkDb = null;
39
40 /**
41 * @var string Dummy page cache
42 */
43 protected $pagecache = 'tests';
44
45 /**
46 * Resets test data before each test
47 */
48 protected function setUp()
49 {
50 if (file_exists(self::$testDatastore)) {
51 unlink(self::$testDatastore);
52 }
53 // start with an empty datastore
54 file_put_contents(self::$testDatastore, '<?php /* S7QysKquBQA= */ ?>');
55 $this->linkDb = new LinkDB(self::$testDatastore, true, false);
56 }
57
58 /**
59 * Attempt to import bookmarks from an empty file
60 */
61 public function testImportEmptyData()
62 {
63 $files = file2array('empty.htm');
64 $this->assertEquals(
65 'File empty.htm (0 bytes) has an unknown file format.'
66 .' Nothing was imported.',
67 NetscapeBookmarkUtils::import(NULL, $files, NULL, NULL)
68 );
69 $this->assertEquals(0, count($this->linkDb));
70 }
71
72 /**
73 * Attempt to import bookmarks from a file with no Doctype
74 */
75 public function testImportNoDoctype()
76 {
77 $files = file2array('no_doctype.htm');
78 $this->assertEquals(
79 'File no_doctype.htm (350 bytes) has an unknown file format. Nothing was imported.',
80 NetscapeBookmarkUtils::import(NULL, $files, NULL, NULL)
81 );
82 $this->assertEquals(0, count($this->linkDb));
83 }
84
85 /**
86 * Import bookmarks nested in a folder hierarchy
87 */
88 public function testImportNested()
89 {
90 $files = file2array('netscape_nested.htm');
91 $this->assertEquals(
92 'File netscape_nested.htm (1337 bytes) was successfully processed:'
93 .' 8 links imported, 0 links overwritten, 0 links skipped.',
94 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache)
95 );
96 $this->assertEquals(8, count($this->linkDb));
97 $this->assertEquals(2, count_private($this->linkDb));
98
99 $this->assertEquals(
100 array(
101 'linkdate' => '20160225_205541',
102 'title' => 'Nested 1',
103 'url' => 'http://nest.ed/1',
104 'description' => '',
105 'private' => 0,
106 'tags' => 'tag1 tag2'
107 ),
108 $this->linkDb->getLinkFromUrl('http://nest.ed/1')
109 );
110 $this->assertEquals(
111 array(
112 'linkdate' => '20160225_205542',
113 'title' => 'Nested 1-1',
114 'url' => 'http://nest.ed/1-1',
115 'description' => '',
116 'private' => 0,
117 'tags' => 'folder1 tag1 tag2'
118 ),
119 $this->linkDb->getLinkFromUrl('http://nest.ed/1-1')
120 );
121 $this->assertEquals(
122 array(
123 'linkdate' => '20160225_205547',
124 'title' => 'Nested 1-2',
125 'url' => 'http://nest.ed/1-2',
126 'description' => '',
127 'private' => 0,
128 'tags' => 'folder1 tag3 tag4'
129 ),
130 $this->linkDb->getLinkFromUrl('http://nest.ed/1-2')
131 );
132 $this->assertEquals(
133 array(
134 'linkdate' => '20160202_172222',
135 'title' => 'Nested 2-1',
136 'url' => 'http://nest.ed/2-1',
137 'description' => 'First link of the second section',
138 'private' => 1,
139 'tags' => 'folder2'
140 ),
141 $this->linkDb->getLinkFromUrl('http://nest.ed/2-1')
142 );
143 $this->assertEquals(
144 array(
145 'linkdate' => '20160119_200227',
146 'title' => 'Nested 2-2',
147 'url' => 'http://nest.ed/2-2',
148 'description' => 'Second link of the second section',
149 'private' => 1,
150 'tags' => 'folder2'
151 ),
152 $this->linkDb->getLinkFromUrl('http://nest.ed/2-2')
153 );
154 $this->assertEquals(
155 array(
156 'linkdate' => '20160202_172223',
157 'title' => 'Nested 3-1',
158 'url' => 'http://nest.ed/3-1',
159 'description' => '',
160 'private' => 0,
161 'tags' => 'folder3 folder3-1 tag3'
162 ),
163 $this->linkDb->getLinkFromUrl('http://nest.ed/3-1')
164 );
165 $this->assertEquals(
166 array(
167 'linkdate' => '20160119_200228',
168 'title' => 'Nested 3-2',
169 'url' => 'http://nest.ed/3-2',
170 'description' => '',
171 'private' => 0,
172 'tags' => 'folder3 folder3-1'
173 ),
174 $this->linkDb->getLinkFromUrl('http://nest.ed/3-2')
175 );
176 $this->assertEquals(
177 array(
178 'linkdate' => '20160229_081541',
179 'title' => 'Nested 2',
180 'url' => 'http://nest.ed/2',
181 'description' => '',
182 'private' => 0,
183 'tags' => 'tag4'
184 ),
185 $this->linkDb->getLinkFromUrl('http://nest.ed/2')
186 );
187 }
188
189 /**
190 * Import bookmarks with the default privacy setting (reuse from file)
191 *
192 * The $_POST array is not set.
193 */
194 public function testImportDefaultPrivacyNoPost()
195 {
196 $files = file2array('netscape_basic.htm');
197 $this->assertEquals(
198 'File netscape_basic.htm (482 bytes) was successfully processed:'
199 .' 2 links imported, 0 links overwritten, 0 links skipped.',
200 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache)
201 );
202 $this->assertEquals(2, count($this->linkDb));
203 $this->assertEquals(1, count_private($this->linkDb));
204
205 $this->assertEquals(
206 array(
207 'linkdate' => '20001010_105536',
208 'title' => 'Secret stuff',
209 'url' => 'https://private.tld',
210 'description' => "Super-secret stuff you're not supposed to know about",
211 'private' => 1,
212 'tags' => 'private secret'
213 ),
214 $this->linkDb->getLinkFromUrl('https://private.tld')
215 );
216 $this->assertEquals(
217 array(
218 'linkdate' => '20160225_205548',
219 'title' => 'Public stuff',
220 'url' => 'http://public.tld',
221 'description' => '',
222 'private' => 0,
223 'tags' => 'public hello world'
224 ),
225 $this->linkDb->getLinkFromUrl('http://public.tld')
226 );
227 }
228
229 /**
230 * Import bookmarks with the default privacy setting (reuse from file)
231 */
232 public function testImportKeepPrivacy()
233 {
234 $post = array('privacy' => 'default');
235 $files = file2array('netscape_basic.htm');
236 $this->assertEquals(
237 'File netscape_basic.htm (482 bytes) was successfully processed:'
238 .' 2 links imported, 0 links overwritten, 0 links skipped.',
239 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
240 );
241 $this->assertEquals(2, count($this->linkDb));
242 $this->assertEquals(1, count_private($this->linkDb));
243
244 $this->assertEquals(
245 array(
246 'linkdate' => '20001010_105536',
247 'title' => 'Secret stuff',
248 'url' => 'https://private.tld',
249 'description' => "Super-secret stuff you're not supposed to know about",
250 'private' => 1,
251 'tags' => 'private secret'
252 ),
253 $this->linkDb->getLinkFromUrl('https://private.tld')
254 );
255 $this->assertEquals(
256 array(
257 'linkdate' => '20160225_205548',
258 'title' => 'Public stuff',
259 'url' => 'http://public.tld',
260 'description' => '',
261 'private' => 0,
262 'tags' => 'public hello world'
263 ),
264 $this->linkDb->getLinkFromUrl('http://public.tld')
265 );
266 }
267
268 /**
269 * Import links as public
270 */
271 public function testImportAsPublic()
272 {
273 $post = array('privacy' => 'public');
274 $files = file2array('netscape_basic.htm');
275 $this->assertEquals(
276 'File netscape_basic.htm (482 bytes) was successfully processed:'
277 .' 2 links imported, 0 links overwritten, 0 links skipped.',
278 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
279 );
280 $this->assertEquals(2, count($this->linkDb));
281 $this->assertEquals(0, count_private($this->linkDb));
282 $this->assertEquals(
283 0,
284 $this->linkDb['20001010_105536']['private']
285 );
286 $this->assertEquals(
287 0,
288 $this->linkDb['20160225_205548']['private']
289 );
290 }
291
292 /**
293 * Import links as private
294 */
295 public function testImportAsPrivate()
296 {
297 $post = array('privacy' => 'private');
298 $files = file2array('netscape_basic.htm');
299 $this->assertEquals(
300 'File netscape_basic.htm (482 bytes) was successfully processed:'
301 .' 2 links imported, 0 links overwritten, 0 links skipped.',
302 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
303 );
304 $this->assertEquals(2, count($this->linkDb));
305 $this->assertEquals(2, count_private($this->linkDb));
306 $this->assertEquals(
307 1,
308 $this->linkDb['20001010_105536']['private']
309 );
310 $this->assertEquals(
311 1,
312 $this->linkDb['20160225_205548']['private']
313 );
314 }
315
316 /**
317 * Overwrite private links so they become public
318 */
319 public function testOverwriteAsPublic()
320 {
321 $files = file2array('netscape_basic.htm');
322
323 // import links as private
324 $post = array('privacy' => 'private');
325 $this->assertEquals(
326 'File netscape_basic.htm (482 bytes) was successfully processed:'
327 .' 2 links imported, 0 links overwritten, 0 links skipped.',
328 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
329 );
330 $this->assertEquals(2, count($this->linkDb));
331 $this->assertEquals(2, count_private($this->linkDb));
332 $this->assertEquals(
333 1,
334 $this->linkDb['20001010_105536']['private']
335 );
336 $this->assertEquals(
337 1,
338 $this->linkDb['20160225_205548']['private']
339 );
340
341 // re-import as public, enable overwriting
342 $post = array(
343 'privacy' => 'public',
344 'overwrite' => 'true'
345 );
346 $this->assertEquals(
347 'File netscape_basic.htm (482 bytes) was successfully processed:'
348 .' 2 links imported, 2 links overwritten, 0 links skipped.',
349 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
350 );
351 $this->assertEquals(2, count($this->linkDb));
352 $this->assertEquals(0, count_private($this->linkDb));
353 $this->assertEquals(
354 0,
355 $this->linkDb['20001010_105536']['private']
356 );
357 $this->assertEquals(
358 0,
359 $this->linkDb['20160225_205548']['private']
360 );
361 }
362
363 /**
364 * Overwrite public links so they become private
365 */
366 public function testOverwriteAsPrivate()
367 {
368 $files = file2array('netscape_basic.htm');
369
370 // import links as public
371 $post = array('privacy' => 'public');
372 $this->assertEquals(
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)
376 );
377 $this->assertEquals(2, count($this->linkDb));
378 $this->assertEquals(0, count_private($this->linkDb));
379 $this->assertEquals(
380 0,
381 $this->linkDb['20001010_105536']['private']
382 );
383 $this->assertEquals(
384 0,
385 $this->linkDb['20160225_205548']['private']
386 );
387
388 // re-import as private, enable overwriting
389 $post = array(
390 'privacy' => 'private',
391 'overwrite' => 'true'
392 );
393 $this->assertEquals(
394 'File netscape_basic.htm (482 bytes) was successfully processed:'
395 .' 2 links imported, 2 links overwritten, 0 links skipped.',
396 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
397 );
398 $this->assertEquals(2, count($this->linkDb));
399 $this->assertEquals(2, count_private($this->linkDb));
400 $this->assertEquals(
401 1,
402 $this->linkDb['20001010_105536']['private']
403 );
404 $this->assertEquals(
405 1,
406 $this->linkDb['20160225_205548']['private']
407 );
408 }
409
410 /**
411 * Attept to import the same links twice without enabling overwriting
412 */
413 public function testSkipOverwrite()
414 {
415 $post = array('privacy' => 'public');
416 $files = file2array('netscape_basic.htm');
417 $this->assertEquals(
418 'File netscape_basic.htm (482 bytes) was successfully processed:'
419 .' 2 links imported, 0 links overwritten, 0 links skipped.',
420 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
421 );
422 $this->assertEquals(2, count($this->linkDb));
423 $this->assertEquals(0, count_private($this->linkDb));
424
425 // re-import as private, DO NOT enable overwriting
426 $post = array('privacy' => 'private');
427 $this->assertEquals(
428 'File netscape_basic.htm (482 bytes) was successfully processed:'
429 .' 0 links imported, 0 links overwritten, 2 links skipped.',
430 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
431 );
432 $this->assertEquals(2, count($this->linkDb));
433 $this->assertEquals(0, count_private($this->linkDb));
434 }
435
436 /**
437 * Add user-specified tags to all imported bookmarks
438 */
439 public function testSetDefaultTags()
440 {
441 $post = array(
442 'privacy' => 'public',
443 'default_tags' => 'tag1,tag2 tag3'
444 );
445 $files = file2array('netscape_basic.htm');
446 $this->assertEquals(
447 'File netscape_basic.htm (482 bytes) was successfully processed:'
448 .' 2 links imported, 0 links overwritten, 0 links skipped.',
449 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
450 );
451 $this->assertEquals(2, count($this->linkDb));
452 $this->assertEquals(0, count_private($this->linkDb));
453 $this->assertEquals(
454 'tag1 tag2 tag3 private secret',
455 $this->linkDb['20001010_105536']['tags']
456 );
457 $this->assertEquals(
458 'tag1 tag2 tag3 public hello world',
459 $this->linkDb['20160225_205548']['tags']
460 );
461 }
462
463 /**
464 * The user-specified tags contain characters to be escaped
465 */
466 public function testSanitizeDefaultTags()
467 {
468 $post = array(
469 'privacy' => 'public',
470 'default_tags' => 'tag1&,tag2 "tag3"'
471 );
472 $files = file2array('netscape_basic.htm');
473 $this->assertEquals(
474 'File netscape_basic.htm (482 bytes) was successfully processed:'
475 .' 2 links imported, 0 links overwritten, 0 links skipped.',
476 NetscapeBookmarkUtils::import($post, $files, $this->linkDb, $this->pagecache)
477 );
478 $this->assertEquals(2, count($this->linkDb));
479 $this->assertEquals(0, count_private($this->linkDb));
480 $this->assertEquals(
481 'tag1&amp; tag2 &quot;tag3&quot; private secret',
482 $this->linkDb['20001010_105536']['tags']
483 );
484 $this->assertEquals(
485 'tag1&amp; tag2 &quot;tag3&quot; public hello world',
486 $this->linkDb['20160225_205548']['tags']
487 );
488 }
489
490 /**
491 * Ensure each imported bookmark has a unique linkdate
492 *
493 * See https://github.com/shaarli/Shaarli/issues/351
494 */
495 public function testImportSameDate()
496 {
497 $files = file2array('same_date.htm');
498 $this->assertEquals(
499 'File same_date.htm (453 bytes) was successfully processed:'
500 .' 3 links imported, 0 links overwritten, 0 links skipped.',
501 NetscapeBookmarkUtils::import(array(), $files, $this->linkDb, $this->pagecache)
502 );
503 $this->assertEquals(3, count($this->linkDb));
504 $this->assertEquals(0, count_private($this->linkDb));
505 $this->assertEquals(
506 '20160225_205548',
507 $this->linkDb['20160225_205548']['linkdate']
508 );
509 $this->assertEquals(
510 '20160225_205549',
511 $this->linkDb['20160225_205549']['linkdate']
512 );
513 $this->assertEquals(
514 '20160225_205550',
515 $this->linkDb['20160225_205550']['linkdate']
516 );
517 }
518}
diff --git a/tests/NetscapeBookmarkUtils/input/empty.htm b/tests/NetscapeBookmarkUtils/input/empty.htm
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/NetscapeBookmarkUtils/input/empty.htm
diff --git a/tests/NetscapeBookmarkUtils/input/netscape_basic.htm b/tests/NetscapeBookmarkUtils/input/netscape_basic.htm
new file mode 100644
index 00000000..affe0cf8
--- /dev/null
+++ b/tests/NetscapeBookmarkUtils/input/netscape_basic.htm
@@ -0,0 +1,11 @@
1<!DOCTYPE NETSCAPE-Bookmark-file-1>
2<!-- This is an automatically generated file.
3It will be read and overwritten.
4Do Not Edit! -->
5<TITLE>Bookmarks</TITLE>
6<H1>Bookmarks</H1>
7<DL><p>
8<DT><A HREF="https://private.tld" ADD_DATE="10/Oct/2000:13:55:36 +0300" PRIVATE="1" TAGS="private secret">Secret stuff</A>
9<DD>Super-secret stuff you're not supposed to know about
10<DT><A HREF="http://public.tld" ADD_DATE="1456433748" PRIVATE="0" TAGS="public hello world">Public stuff</A>
11</DL><p>
diff --git a/tests/NetscapeBookmarkUtils/input/netscape_nested.htm b/tests/NetscapeBookmarkUtils/input/netscape_nested.htm
new file mode 100644
index 00000000..b486fe18
--- /dev/null
+++ b/tests/NetscapeBookmarkUtils/input/netscape_nested.htm
@@ -0,0 +1,31 @@
1<!DOCTYPE NETSCAPE-Bookmark-file-1>
2<!-- This is an automatically generated file.
3It will be read and overwritten.
4Do Not Edit! -->
5<TITLE>Bookmarks</TITLE>
6<H1>Bookmarks</H1>
7<DL><p>
8 <DT><A HREF="http://nest.ed/1" ADD_DATE="1456433741" PRIVATE="0" TAGS="tag1,tag2">Nested 1</A>
9 <DT><H3 ADD_DATE="1456433722" LAST_MODIFIED="1456433739">Folder1</H3>
10 <DL><p>
11 <DT><A HREF="http://nest.ed/1-1" ADD_DATE="1456433742" PRIVATE="0" TAGS="tag1,tag2">Nested 1-1</A>
12 <DT><A HREF="http://nest.ed/1-2" ADD_DATE="1456433747" PRIVATE="0" TAGS="tag3,tag4">Nested 1-2</A>
13 </DL><p>
14 <DT><H3 ADD_DATE="1456433722">Folder2</H3>
15 <DD>This second folder contains wonderful links!
16 <DL><p>
17 <DT><A HREF="http://nest.ed/2-1" ADD_DATE="1454433742" PRIVATE="1">Nested 2-1</A>
18 <DD>First link of the second section
19 <DT><A HREF="http://nest.ed/2-2" ADD_DATE="1453233747" PRIVATE="1">Nested 2-2</A>
20 <DD>Second link of the second section
21 </DL><p>
22 <DT><H3>Folder3</H3>
23 <DL><p>
24 <DT><H3>Folder3-1</H3>
25 <DL><p>
26 <DT><A HREF="http://nest.ed/3-1" ADD_DATE="1454433742" PRIVATE="0" TAGS="tag3">Nested 3-1</A>
27 <DT><A HREF="http://nest.ed/3-2" ADD_DATE="1453233747" PRIVATE="0">Nested 3-2</A>
28 </DL><p>
29 </DL><p>
30 <DT><A HREF="http://nest.ed/2" ADD_DATE="1456733741" PRIVATE="0" TAGS="tag4">Nested 2</A>
31</DL><p>
diff --git a/tests/NetscapeBookmarkUtils/input/no_doctype.htm b/tests/NetscapeBookmarkUtils/input/no_doctype.htm
new file mode 100644
index 00000000..766d398b
--- /dev/null
+++ b/tests/NetscapeBookmarkUtils/input/no_doctype.htm
@@ -0,0 +1,7 @@
1<TITLE>Bookmarks</TITLE>
2<H1>Bookmarks</H1>
3<DL><p>
4<DT><A HREF="https://private.tld" ADD_DATE="10/Oct/2000:13:55:36 +0300" PRIVATE="1" TAGS="private secret">Secret stuff</A>
5<DD>Super-secret stuff you're not supposed to know about
6<DT><A HREF="http://public.tld" ADD_DATE="1456433748" PRIVATE="0" TAGS="public hello world">Public stuff</A>
7</DL><p>
diff --git a/tests/NetscapeBookmarkUtils/input/same_date.htm b/tests/NetscapeBookmarkUtils/input/same_date.htm
new file mode 100644
index 00000000..9d58a582
--- /dev/null
+++ b/tests/NetscapeBookmarkUtils/input/same_date.htm
@@ -0,0 +1,11 @@
1<!DOCTYPE NETSCAPE-Bookmark-file-1>
2<!-- This is an automatically generated file.
3It will be read and overwritten.
4Do Not Edit! -->
5<TITLE>Bookmarks</TITLE>
6<H1>Bookmarks</H1>
7<DL><p>
8<DT><A HREF="https://fir.st" ADD_DATE="1456433748" PRIVATE="0">Today's first link</A>
9<DT><A HREF="https://seco.nd" ADD_DATE="1456433748" PRIVATE="0">Today's second link</A>
10<DT><A HREF="https://thi.rd" ADD_DATE="1456433748" PRIVATE="0">Today's third link</A>
11</DL><p>