aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/mikespub/php-epub-meta/test
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/mikespub/php-epub-meta/test')
-rw-r--r--vendor/mikespub/php-epub-meta/test/.gitignore1
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/broken.zipbin0 -> 134 bytes
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/calibre_bookmarks.txt26
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/empty.zipbin0 -> 22 bytes
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/eng.components.json16
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/eng.contents.json96
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/eng.epubbin0 -> 22664 bytes
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/eng3.epubbin0 -> 53216 bytes
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/markup.1.xml41
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/markup.2.xml1175
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/markup.3.xml3
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/markup.4.xml5
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/markup.5.xml860
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/metadata.opf35
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/nav-non-text_img_title.epubbin0 -> 239564 bytes
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/test.epubbin0 -> 768780 bytes
-rw-r--r--vendor/mikespub/php-epub-meta/test/data/test.jpgbin0 -> 821 bytes
-rw-r--r--vendor/mikespub/php-epub-meta/test/epubTest.php807
-rw-r--r--vendor/mikespub/php-epub-meta/test/monocleTest.php159
19 files changed, 3224 insertions, 0 deletions
diff --git a/vendor/mikespub/php-epub-meta/test/.gitignore b/vendor/mikespub/php-epub-meta/test/.gitignore
new file mode 100644
index 000000000..46e7bc5e7
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/.gitignore
@@ -0,0 +1 @@
+data/test.cover.epub
diff --git a/vendor/mikespub/php-epub-meta/test/data/broken.zip b/vendor/mikespub/php-epub-meta/test/data/broken.zip
new file mode 100644
index 000000000..0c407313c
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/broken.zip
Binary files differ
diff --git a/vendor/mikespub/php-epub-meta/test/data/calibre_bookmarks.txt b/vendor/mikespub/php-epub-meta/test/data/calibre_bookmarks.txt
new file mode 100644
index 000000000..f4d518ab8
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/calibre_bookmarks.txt
@@ -0,0 +1,26 @@
+encoding=json+base64:
+W3sidGl0bGUiOiAiQWJvdXQgIzEiLCAicG9zX3R5cGUiOiAiZXB1YmNmaSIsICJwb3MiOiAiZXB1YmNm
+aSgvNi8yLzQvMi82LzI6MzgpIiwgInRpbWVzdGFtcCI6ICIyMDI0LTAzLTExVDExOjU0OjM1LjEyODM5
+NiswMDowMCIsICJ0eXBlIjogImJvb2ttYXJrIn0sIHsicG9zIjogImVwdWJjZmkoLzgvMi80LzIvMltj
+aGFwdGVyXzQ1OF0vNC80LzE6Mjg3KSIsICJwb3NfdHlwZSI6ICJlcHViY2ZpIiwgInRpbWVzdGFtcCI6
+ICIyMDI0LTAzLTExVDExOjU3OjUxLjAwMDM4NyswMDowMCIsICJ0eXBlIjogImxhc3QtcmVhZCJ9LCB7
+ImVuZF9jZmkiOiAiLzIvNC8yLzIvNi8xOjI0IiwgImhpZ2hsaWdodGVkX3RleHQiOiAiQ2hhcmxlcyBM
+dXR3aWRnZSBEb2Rnc29uIiwgIm5vdGVzIjogIkZ1bGwgYXV0aG9yIG5hbWUiLCAic3BpbmVfaW5kZXgi
+OiAyLCAic3BpbmVfbmFtZSI6ICJPUFMvYWJvdXQueG1sIiwgInN0YXJ0X2NmaSI6ICIvMi80LzIvMi82
+LzE6MCIsICJzdHlsZSI6IHsia2luZCI6ICJjb2xvciIsICJ0eXBlIjogImJ1aWx0aW4iLCAid2hpY2gi
+OiAieWVsbG93In0sICJ0aW1lc3RhbXAiOiAiMjAyNC0wMy0xMVQxMTo1Mzo1NS41ODNaIiwgInRvY19m
+YW1pbHlfdGl0bGVzIjogWyJBYm91dCJdLCAidHlwZSI6ICJoaWdobGlnaHQiLCAidXVpZCI6ICI1SEhH
+dW9DT3RwQS11bWFJYkJ1YzBRIn0sIHsiZW5kX2NmaSI6ICIvMi80LzIvMi82LzE6MTA2IiwgImhpZ2hs
+aWdodGVkX3RleHQiOiAiTGV3aXMgQ2Fycm9sbCIsICJzcGluZV9pbmRleCI6IDIsICJzcGluZV9uYW1l
+IjogIk9QUy9hYm91dC54bWwiLCAic3RhcnRfY2ZpIjogIi8yLzQvMi8yLzYvMTo5MyIsICJzdHlsZSI6
+IHsia2luZCI6ICJjb2xvciIsICJ0eXBlIjogImJ1aWx0aW4iLCAid2hpY2giOiAieWVsbG93In0sICJ0
+aW1lc3RhbXAiOiAiMjAyNC0wMy0xMVQxMTo1NTozMi43MzRaIiwgInRvY19mYW1pbHlfdGl0bGVzIjog
+WyJBYm91dCJdLCAidHlwZSI6ICJoaWdobGlnaHQiLCAidXVpZCI6ICJpdUdUeS1XSVhXRGluQnVzenBw
+R3dBIn0sIHsiZW5kX2NmaSI6ICIvMi80LzIvMltjaGFwdGVyXzQ1OF0vNC8yLzE6NSIsICJoaWdobGln
+aHRlZF90ZXh0IjogIkFsaWNlIiwgIm5vdGVzIjogIlByb3RhZ29uaXN0IiwgInNwaW5lX2luZGV4Ijog
+MywgInNwaW5lX25hbWUiOiAiT1BTL21haW4wLnhtbCIsICJzdGFydF9jZmkiOiAiLzIvNC8yLzJbY2hh
+cHRlcl80NThdLzQvMi8xOjAiLCAic3R5bGUiOiB7ImtpbmQiOiAiY29sb3IiLCAidHlwZSI6ICJidWls
+dGluIiwgIndoaWNoIjogInllbGxvdyJ9LCAidGltZXN0YW1wIjogIjIwMjQtMDMtMTFUMTE6NTY6NTIu
+ODkxWiIsICJ0b2NfZmFtaWx5X3RpdGxlcyI6IFsiQ2hhcHRlciAxIC0gRG93biB0aGUgUmFiYml0IEhv
+bGUiXSwgInR5cGUiOiAiaGlnaGxpZ2h0IiwgInV1aWQiOiAiS0ZHTlhWQjJIZWI1M2doc0FqVnF2USJ9
+XQ== \ No newline at end of file
diff --git a/vendor/mikespub/php-epub-meta/test/data/empty.zip b/vendor/mikespub/php-epub-meta/test/data/empty.zip
new file mode 100644
index 000000000..15cb0ecb3
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/empty.zip
Binary files differ
diff --git a/vendor/mikespub/php-epub-meta/test/data/eng.components.json b/vendor/mikespub/php-epub-meta/test/data/eng.components.json
new file mode 100644
index 000000000..59e7646f8
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/eng.components.json
@@ -0,0 +1,16 @@
+[
+ "text/titlepage.xhtml",
+ "text/internal_titlepage.xhtml",
+ "text/toc.xhtml",
+ "text/introduction.xhtml",
+ "text/installing_calibre.xhtml",
+ "text/the_main_gui_window.xhtml",
+ "text/common_tasks.xhtml",
+ "text/task_1_organizing.xhtml",
+ "text/task_2_conversion.xhtml",
+ "text/task_3_the_ebook_editor.xhtml",
+ "text/task_4_downloading_news.xhtml",
+ "text/task_5_interacting_with_ebook_readers.xhtml",
+ "text/task_6_the_ebook_viewer.xhtml",
+ "text/where_to_get_help.xhtml"
+] \ No newline at end of file
diff --git a/vendor/mikespub/php-epub-meta/test/data/eng.contents.json b/vendor/mikespub/php-epub-meta/test/data/eng.contents.json
new file mode 100644
index 000000000..90dd2208e
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/eng.contents.json
@@ -0,0 +1,96 @@
+[
+ {
+ "title": "Calibre Quick Start Guide",
+ "src": "text/internal_titlepage.xhtml"
+ },
+ {
+ "title": "Table of Contents",
+ "src": "text/toc.xhtml"
+ },
+ {
+ "title": "Introduction",
+ "src": "text/introduction.xhtml"
+ },
+ {
+ "title": "Installing calibre",
+ "src": "text/installing_calibre.xhtml"
+ },
+ {
+ "title": "The Main Library Window, aka the GUI",
+ "src": "text/the_main_gui_window.xhtml"
+ },
+ {
+ "title": "Common Tasks",
+ "src": "text/common_tasks.xhtml",
+ "children": [
+ {
+ "title": "Task 1: Organizing",
+ "src": "text/task_1_organizing.xhtml"
+ },
+ {
+ "title": "Task 2: Conversion",
+ "src": "text/task_2_conversion.xhtml",
+ "children": [
+ {
+ "title": "2.1: Background",
+ "src": "text/task_2_conversion.xhtml#task2.1"
+ },
+ {
+ "title": "2.2: Why are there different e-book formats?",
+ "src": "text/task_2_conversion.xhtml#task2.2"
+ },
+ {
+ "title": "2.3: Conversion basics",
+ "src": "text/task_2_conversion.xhtml#task2.3"
+ },
+ {
+ "title": "2.4: Auto Conversion",
+ "src": "text/task_2_conversion.xhtml#task2.4"
+ },
+ {
+ "title": "2.5: More robust conversion",
+ "src": "text/task_2_conversion.xhtml#task2.5"
+ },
+ {
+ "title": "2.6: Limitations of conversion",
+ "src": "text/task_2_conversion.xhtml#task2.6"
+ },
+ {
+ "title": "2.7: DRM: the bane of conversion",
+ "src": "text/task_2_conversion.xhtml#task2.7"
+ }
+ ]
+ },
+ {
+ "title": "Task 3: The e-book editor",
+ "src": "text/task_3_the_ebook_editor.xhtml"
+ },
+ {
+ "title": "Task 4: Downloading News",
+ "src": "text/task_4_downloading_news.xhtml"
+ },
+ {
+ "title": "Task 5: Interacting with e-book readers",
+ "src": "text/task_5_interacting_with_ebook_readers.xhtml",
+ "children": [
+ {
+ "title": "5.1: Putting an e-book on your e-book reader",
+ "src": "text/task_5_interacting_with_ebook_readers.xhtml#task5.1"
+ },
+ {
+ "title": "5.2: E-book reader optional configuration",
+ "src": "text/task_5_interacting_with_ebook_readers.xhtml#task5.2"
+ }
+ ]
+ },
+ {
+ "title": "Task 6: The e-book viewer",
+ "src": "text/task_6_the_ebook_viewer.xhtml"
+ }
+ ]
+ },
+ {
+ "title": "Where to get help",
+ "src": "text/where_to_get_help.xhtml"
+ }
+]
diff --git a/vendor/mikespub/php-epub-meta/test/data/eng.epub b/vendor/mikespub/php-epub-meta/test/data/eng.epub
new file mode 100644
index 000000000..fd256d41a
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/eng.epub
Binary files differ
diff --git a/vendor/mikespub/php-epub-meta/test/data/eng3.epub b/vendor/mikespub/php-epub-meta/test/data/eng3.epub
new file mode 100644
index 000000000..5fad2dd76
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/eng3.epub
Binary files differ
diff --git a/vendor/mikespub/php-epub-meta/test/data/markup.1.xml b/vendor/mikespub/php-epub-meta/test/data/markup.1.xml
new file mode 100644
index 000000000..ac1e50e57
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/markup.1.xml
@@ -0,0 +1,41 @@
+<div>
+ <div>
+ <h3>Act I</h3>
+ <div>
+ <h3>Prologue</h3>
+ <div>
+
+ <p>Two households, both alike in dignity,
+ <br />
+ In fair Verona, where we lay our scene,
+ <br />
+ From ancient grudge break to new mutiny,
+ <br />
+ Where civil blood makes civil hands unclean.
+ <br />
+ From forth the fatal loins of these two foes
+ <br />
+ A pair of star-cross'd lovers take their life;
+ <br />
+ Whole misadventured piteous overthrows
+ <br />
+ Do with their death bury their parents' strife.
+ <br />
+ The fearful passage of their death-mark'd love,
+ <br />
+ And the continuance of their parents' rage,
+ <br />
+ Which, but their children's end, nought could remove,
+ <br />
+ Is now the two hours' traffic of our stage;
+ <br />
+ The which if you with patient ears attend,
+ <br />
+ What here shall miss, our toil shall strive to mend.
+ </p>
+
+
+ </div>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/vendor/mikespub/php-epub-meta/test/data/markup.2.xml b/vendor/mikespub/php-epub-meta/test/data/markup.2.xml
new file mode 100644
index 000000000..643df54a7
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/markup.2.xml
@@ -0,0 +1,1175 @@
+<div>
+ <div>
+ <h3>SCENE I. Verona. A public place.</h3>
+ <div>
+
+ <p>Enter SAMPSON and GREGORY, of the house of Capulet, armed
+ with swords and bucklers
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Gregory, o' my word, we'll not carry coals.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>No, for then we should be colliers.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>I mean, an we be in choler, we'll draw.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>Ay, while you live, draw your neck out o' the collar.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>I strike quickly, being moved.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>But thou art not quickly moved to strike.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>A dog of the house of Montague moves me.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>To move is to stir; and to be valiant is to stand:
+ <br />
+ therefore, if thou art moved, thou runn'st away.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>A dog of that house shall move me to stand: I will
+ <br />
+ take the wall of any man or maid of Montague's.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>That shows thee a weak slave; for the weakest goes
+ <br />
+ to the wall.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>True; and therefore women, being the weaker vessels,
+ <br />
+ are ever thrust to the wall: therefore I will push
+ <br />
+ Montague's men from the wall, and thrust his maids
+ <br />
+ to the wall.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>The quarrel is between our masters and us their men.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>'Tis all one, I will show myself a tyrant: when I
+ <br />
+ have fought with the men, I will be cruel with the
+ <br />
+ maids, and cut off their heads.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>The heads of the maids?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Ay, the heads of the maids, or their maidenheads;
+ <br />
+ take it in what sense thou wilt.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>They must take it in sense that feel it.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Me they shall feel while I am able to stand: and
+ <br />
+ 'tis known I am a pretty piece of flesh.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>'Tis well thou art not fish; if thou hadst, thou
+ <br />
+ hadst been poor John. Draw thy tool! here comes
+ <br />
+ two of the house of the Montagues.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>My naked weapon is out: quarrel, I will back thee.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>How! turn thy back and run?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Fear me not.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>No, marry; I fear thee!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Let us take the law of our sides; let them begin.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>I will frown as I pass by, and let them take it as
+ <br />
+ they list.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Nay, as they dare. I will bite my thumb at them;
+ <br />
+ which is a disgrace to them, if they bear it.
+ <br />
+ </p>
+ <p>Enter ABRAHAM and BALTHASAR</p>
+
+
+ <p>
+ <strong>ABRAHAM</strong>
+ </p>
+
+ <p>Do you bite your thumb at us, sir?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>I do bite my thumb, sir.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ABRAHAM</strong>
+ </p>
+
+ <p>Do you bite your thumb at us, sir?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>[Aside to GREGORY] Is the law of our side, if I say
+ <br />
+ ay?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>No.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>No, sir, I do not bite my thumb at you, sir, but I
+ <br />
+ bite my thumb, sir.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>Do you quarrel, sir?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ABRAHAM</strong>
+ </p>
+
+ <p>Quarrel sir! no, sir.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>If you do, sir, I am for you: I serve as good a man as
+ you.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ABRAHAM</strong>
+ </p>
+
+ <p>No better.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Well, sir.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>GREGORY</strong>
+ </p>
+
+ <p>Say 'better:' here comes one of my master's kinsmen.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Yes, better, sir.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ABRAHAM</strong>
+ </p>
+
+ <p>You lie.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>SAMPSON</strong>
+ </p>
+
+ <p>Draw, if you be men. Gregory, remember thy swashing
+ blow.
+ <br />
+ </p>
+ <p>They fight</p>
+ <p>Enter BENVOLIO</p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Part, fools!
+ <br />
+ Put up your swords; you know not what you do.
+ <br />
+ </p>
+ <p>Beats down their swords</p>
+ <p>Enter TYBALT</p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>What, art thou drawn among these heartless hinds?
+ <br />
+ Turn thee, Benvolio, look upon thy death.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>I do but keep the peace: put up thy sword,
+ <br />
+ Or manage it to part these men with me.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>What, drawn, and talk of peace! I hate the word,
+ <br />
+ As I hate hell, all Montagues, and thee:
+ <br />
+ Have at thee, coward!
+ <br />
+ </p>
+ <p>They fight</p>
+ <p>Enter, several of both houses, who join the fray; then enter
+ Citizens, with clubs
+ </p>
+
+
+ <p>
+ <strong>First Citizen</strong>
+ </p>
+
+ <p>Clubs, bills, and partisans! strike! beat them down!
+ <br />
+ Down with the Capulets! down with the Montagues!
+ <br />
+ </p>
+ <p>Enter CAPULET in his gown, and LADY CAPULET</p>
+
+
+ <p>
+ <strong>CAPULET</strong>
+ </p>
+
+ <p>What noise is this? Give me my long sword, ho!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>LADY CAPULET</strong>
+ </p>
+
+ <p>A crutch, a crutch! why call you for a sword?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>CAPULET</strong>
+ </p>
+
+ <p>My sword, I say! Old Montague is come,
+ <br />
+ And flourishes his blade in spite of me.
+ <br />
+ </p>
+ <p>Enter MONTAGUE and LADY MONTAGUE</p>
+
+
+ <p>
+ <strong>MONTAGUE</strong>
+ </p>
+
+ <p>Thou villain Capulet,—Hold me not, let me go.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>LADY MONTAGUE</strong>
+ </p>
+
+ <p>Thou shalt not stir a foot to seek a foe.
+ <br />
+ </p>
+ <p>Enter PRINCE, with Attendants</p>
+
+
+ <p>
+ <strong>PRINCE</strong>
+ </p>
+
+ <p>Rebellious subjects, enemies to peace,
+ <br />
+ Profaners of this neighbour-stained steel,—
+ <br />
+ Will they not hear? What, ho! you men, you beasts,
+ <br />
+ That quench the fire of your pernicious rage
+ <br />
+ With purple fountains issuing from your veins,
+ <br />
+ On pain of torture, from those bloody hands
+ <br />
+ Throw your mistemper'd weapons to the ground,
+ <br />
+ And hear the sentence of your moved prince.
+ <br />
+ Three civil brawls, bred of an airy word,
+ <br />
+ By thee, old Capulet, and Montague,
+ <br />
+ Have thrice disturb'd the quiet of our streets,
+ <br />
+ And made Verona's ancient citizens
+ <br />
+ Cast by their grave beseeming ornaments,
+ <br />
+ To wield old partisans, in hands as old,
+ <br />
+ Canker'd with peace, to part your canker'd hate:
+ <br />
+ If ever you disturb our streets again,
+ <br />
+ Your lives shall pay the forfeit of the peace.
+ <br />
+ For this time, all the rest depart away:
+ <br />
+ You Capulet; shall go along with me:
+ <br />
+ And, Montague, come you this afternoon,
+ <br />
+ To know our further pleasure in this case,
+ <br />
+ To old Free-town, our common judgment-place.
+ <br />
+ Once more, on pain of death, all men depart.
+ <br />
+ </p>
+ <p>Exeunt all but MONTAGUE, LADY MONTAGUE, and
+ BENVOLIO
+ </p>
+
+
+ <p>
+ <strong>MONTAGUE</strong>
+ </p>
+
+ <p>Who set this ancient quarrel new abroach?
+ <br />
+ Speak, nephew, were you by when it began?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Here were the servants of your adversary,
+ <br />
+ And yours, close fighting ere I did approach:
+ <br />
+ I drew to part them: in the instant came
+ <br />
+ The fiery Tybalt, with his sword prepared,
+ <br />
+ Which, as he breathed defiance to my ears,
+ <br />
+ He swung about his head and cut the winds,
+ <br />
+ Who nothing hurt withal hiss'd him in scorn:
+ <br />
+ While we were interchanging thrusts and blows,
+ <br />
+ Came more and more and fought on part and part,
+ <br />
+ Till the prince came, who parted either part.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>LADY MONTAGUE</strong>
+ </p>
+
+ <p>O, where is Romeo? saw you him to-day?
+ <br />
+ Right glad I am he was not at this fray.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Madam, an hour before the worshipp'd sun
+ <br />
+ Peer'd forth the golden window of the east,
+ <br />
+ A troubled mind drave me to walk abroad;
+ <br />
+ Where, underneath the grove of sycamore
+ <br />
+ That westward rooteth from the city's side,
+ <br />
+ So early walking did I see your son:
+ <br />
+ Towards him I made, but he was ware of me
+ <br />
+ And stole into the covert of the wood:
+ <br />
+ I, measuring his affections by my own,
+ <br />
+ That most are busied when they're most alone,
+ <br />
+ Pursued my humour not pursuing his,
+ <br />
+ And gladly shunn'd who gladly fled from me.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MONTAGUE</strong>
+ </p>
+
+ <p>Many a morning hath he there been seen,
+ <br />
+ With tears augmenting the fresh morning dew.
+ <br />
+ Adding to clouds more clouds with his deep sighs;
+ <br />
+ But all so soon as the all-cheering sun
+ <br />
+ Should in the furthest east begin to draw
+ <br />
+ The shady curtains from Aurora's bed,
+ <br />
+ Away from the light steals home my heavy son,
+ <br />
+ And private in his chamber pens himself,
+ <br />
+ Shuts up his windows, locks far daylight out
+ <br />
+ And makes himself an artificial night:
+ <br />
+ Black and portentous must this humour prove,
+ <br />
+ Unless good counsel may the cause remove.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>My noble uncle, do you know the cause?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MONTAGUE</strong>
+ </p>
+
+ <p>I neither know it nor can learn of him.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Have you importuned him by any means?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MONTAGUE</strong>
+ </p>
+
+ <p>Both by myself and many other friends:
+ <br />
+ But he, his own affections' counsellor,
+ <br />
+ Is to himself—I will not say how true—
+ <br />
+ But to himself so secret and so close,
+ <br />
+ So far from sounding and discovery,
+ <br />
+ As is the bud bit with an envious worm,
+ <br />
+ Ere he can spread his sweet leaves to the air,
+ <br />
+ Or dedicate his beauty to the sun.
+ <br />
+ Could we but learn from whence his sorrows grow.
+ <br />
+ We would as willingly give cure as know.
+ <br />
+ </p>
+ <p>Enter ROMEO</p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>See, where he comes: so please you, step aside;
+ <br />
+ I'll know his grievance, or be much denied.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MONTAGUE</strong>
+ </p>
+
+ <p>I would thou wert so happy by thy stay,
+ <br />
+ To hear true shrift. Come, madam, let's away.
+ <br />
+ </p>
+ <p>Exeunt MONTAGUE and LADY MONTAGUE</p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Good-morrow, cousin.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Is the day so young?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>But new struck nine.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Ay me! sad hours seem long.
+ <br />
+ Was that my father that went hence so fast?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>It was. What sadness lengthens Romeo's hours?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Not having that, which, having, makes them short.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>In love?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Out—
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Of love?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Out of her favour, where I am in love.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Alas, that love, so gentle in his view,
+ <br />
+ Should be so tyrannous and rough in proof!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Alas, that love, whose view is muffled still,
+ <br />
+ Should, without eyes, see pathways to his will!
+ <br />
+ Where shall we dine? O me! What fray was here?
+ <br />
+ Yet tell me not, for I have heard it all.
+ <br />
+ Here's much to do with hate, but more with love.
+ <br />
+ Why, then, O brawling love! O loving hate!
+ <br />
+ O any thing, of nothing first create!
+ <br />
+ O heavy lightness! serious vanity!
+ <br />
+ Mis-shapen chaos of well-seeming forms!
+ <br />
+ Feather of lead, bright smoke, cold fire,
+ <br />
+ sick health!
+ <br />
+ Still-waking sleep, that is not what it is!
+ <br />
+ This love feel I, that feel no love in this.
+ <br />
+ Dost thou not laugh?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>No, coz, I rather weep.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Good heart, at what?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>At thy good heart's oppression.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Why, such is love's transgression.
+ <br />
+ Griefs of mine own lie heavy in my breast,
+ <br />
+ Which thou wilt propagate, to have it prest
+ <br />
+ With more of thine: this love that thou hast shown
+ <br />
+ Doth add more grief to too much of mine own.
+ <br />
+ Love is a smoke raised with the fume of sighs;
+ <br />
+ Being purged, a fire sparkling in lovers' eyes;
+ <br />
+ Being vex'd a sea nourish'd with lovers' tears:
+ <br />
+ What is it else? a madness most discreet,
+ <br />
+ A choking gall and a preserving sweet.
+ <br />
+ Farewell, my coz.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Soft! I will go along;
+ <br />
+ An if you leave me so, you do me wrong.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Tut, I have lost myself; I am not here;
+ <br />
+ This is not Romeo, he's some other where.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Tell me in sadness, who is that you love.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>What, shall I groan and tell thee?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Groan! why, no.
+ <br />
+ But sadly tell me who.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Bid a sick man in sadness make his will:
+ <br />
+ Ah, word ill urged to one that is so ill!
+ <br />
+ In sadness, cousin, I do love a woman.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>I aim'd so near, when I supposed you loved.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>A right good mark-man! And she's fair I love.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>A right fair mark, fair coz, is soonest hit.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Well, in that hit you miss: she'll not be hit
+ <br />
+ With Cupid's arrow; she hath Dian's wit;
+ <br />
+ And, in strong proof of chastity well arm'd,
+ <br />
+ From love's weak childish bow she lives unharm'd.
+ <br />
+ She will not stay the siege of loving terms,
+ <br />
+ Nor bide the encounter of assailing eyes,
+ <br />
+ Nor ope her lap to saint-seducing gold:
+ <br />
+ O, she is rich in beauty, only poor,
+ <br />
+ That when she dies with beauty dies her store.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Then she hath sworn that she will still live chaste?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>She hath, and in that sparing makes huge waste,
+ <br />
+ For beauty starved with her severity
+ <br />
+ Cuts beauty off from all posterity.
+ <br />
+ She is too fair, too wise, wisely too fair,
+ <br />
+ To merit bliss by making me despair:
+ <br />
+ She hath forsworn to love, and in that vow
+ <br />
+ Do I live dead that live to tell it now.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Be ruled by me, forget to think of her.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>O, teach me how I should forget to think.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>By giving liberty unto thine eyes;
+ <br />
+ Examine other beauties.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>'Tis the way
+ <br />
+ To call hers exquisite, in question more:
+ <br />
+ These happy masks that kiss fair ladies' brows
+ <br />
+ Being black put us in mind they hide the fair;
+ <br />
+ He that is strucken blind cannot forget
+ <br />
+ The precious treasure of his eyesight lost:
+ <br />
+ Show me a mistress that is passing fair,
+ <br />
+ What doth her beauty serve, but as a note
+ <br />
+ Where I may read who pass'd that passing fair?
+ <br />
+ Farewell: thou canst not teach me to forget.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>I'll pay that doctrine, or else die in debt.
+ <br />
+ </p>
+ <p>Exeunt</p>
+
+
+ </div>
+ </div>
+</div>
+
diff --git a/vendor/mikespub/php-epub-meta/test/data/markup.3.xml b/vendor/mikespub/php-epub-meta/test/data/markup.3.xml
new file mode 100644
index 000000000..58ffb5d11
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/markup.3.xml
@@ -0,0 +1,3 @@
+<div>
+ <h3>Act III</h3>
+</div> \ No newline at end of file
diff --git a/vendor/mikespub/php-epub-meta/test/data/markup.4.xml b/vendor/mikespub/php-epub-meta/test/data/markup.4.xml
new file mode 100644
index 000000000..fdda27bac
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/markup.4.xml
@@ -0,0 +1,5 @@
+<div>
+ <div>
+ <h3>Act III</h3>
+ </div>
+</div> \ No newline at end of file
diff --git a/vendor/mikespub/php-epub-meta/test/data/markup.5.xml b/vendor/mikespub/php-epub-meta/test/data/markup.5.xml
new file mode 100644
index 000000000..52e046b5c
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/markup.5.xml
@@ -0,0 +1,860 @@
+<div>
+ <h3>SCENE I. A public place.</h3>
+ <div>
+
+ <p>Enter MERCUTIO, BENVOLIO, Page, and Servants</p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>I pray thee, good Mercutio, let's retire:
+ <br />
+ The day is hot, the Capulets abroad,
+ <br />
+ And, if we meet, we shall not scape a brawl;
+ <br />
+ For now, these hot days, is the mad blood stirring.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Thou art like one of those fellows that when he
+ <br />
+ enters the confines of a tavern claps me his sword
+ <br />
+ upon the table and says 'God send me no need of
+ <br />
+ thee!' and by the operation of the second cup draws
+ <br />
+ it on the drawer, when indeed there is no need.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Am I like such a fellow?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Come, come, thou art as hot a Jack in thy mood as
+ <br />
+ any in Italy, and as soon moved to be moody, and as
+ <br />
+ soon moody to be moved.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>And what to?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Nay, an there were two such, we should have none
+ <br />
+ shortly, for one would kill the other. Thou! why,
+ <br />
+ thou wilt quarrel with a man that hath a hair more,
+ <br />
+ or a hair less, in his beard, than thou hast: thou
+ <br />
+ wilt quarrel with a man for cracking nuts, having no
+ <br />
+ other reason but because thou hast hazel eyes: what
+ <br />
+ eye but such an eye would spy out such a quarrel?
+ <br />
+ Thy head is as fun of quarrels as an egg is full of
+ <br />
+ meat, and yet thy head hath been beaten as addle as
+ <br />
+ an egg for quarrelling: thou hast quarrelled with a
+ <br />
+ man for coughing in the street, because he hath
+ <br />
+ wakened thy dog that hath lain asleep in the sun:
+ <br />
+ didst thou not fall out with a tailor for wearing
+ <br />
+ his new doublet before Easter? with another, for
+ <br />
+ tying his new shoes with old riband? and yet thou
+ <br />
+ wilt tutor me from quarrelling!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>An I were so apt to quarrel as thou art, any man
+ <br />
+ should buy the fee-simple of my life for an hour and a
+ quarter.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>The fee-simple! O simple!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>By my head, here come the Capulets.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>By my heel, I care not.
+ <br />
+ </p>
+ <p>Enter TYBALT and others</p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>Follow me close, for I will speak to them.
+ <br />
+ Gentlemen, good den: a word with one of you.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>And but one word with one of us? couple it with
+ <br />
+ something; make it a word and a blow.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>You shall find me apt enough to that, sir, an you
+ <br />
+ will give me occasion.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Could you not take some occasion without giving?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>Mercutio, thou consort'st with Romeo,—
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Consort! what, dost thou make us minstrels? an
+ <br />
+ thou make minstrels of us, look to hear nothing but
+ <br />
+ discords: here's my fiddlestick; here's that shall
+ <br />
+ make you dance. 'Zounds, consort!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>We talk here in the public haunt of men:
+ <br />
+ Either withdraw unto some private place,
+ <br />
+ And reason coldly of your grievances,
+ <br />
+ Or else depart; here all eyes gaze on us.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Men's eyes were made to look, and let them gaze;
+ <br />
+ I will not budge for no man's pleasure, I.
+ <br />
+ </p>
+ <p>Enter ROMEO</p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>Well, peace be with you, sir: here comes my man.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>But I'll be hanged, sir, if he wear your livery:
+ <br />
+ Marry, go before to field, he'll be your follower;
+ <br />
+ Your worship in that sense may call him 'man.'
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>Romeo, the hate I bear thee can afford
+ <br />
+ No better term than this,—thou art a villain.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Tybalt, the reason that I have to love thee
+ <br />
+ Doth much excuse the appertaining rage
+ <br />
+ To such a greeting: villain am I none;
+ <br />
+ Therefore farewell; I see thou know'st me not.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>Boy, this shall not excuse the injuries
+ <br />
+ That thou hast done me; therefore turn and draw.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>I do protest, I never injured thee,
+ <br />
+ But love thee better than thou canst devise,
+ <br />
+ Till thou shalt know the reason of my love:
+ <br />
+ And so, good Capulet,—which name I tender
+ <br />
+ As dearly as my own,—be satisfied.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>O calm, dishonourable, vile submission!
+ <br />
+ Alla stoccata carries it away.
+ <br />
+ </p>
+ <p>Draws</p>
+ <p>Tybalt, you rat-catcher, will you walk?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>What wouldst thou have with me?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Good king of cats, nothing but one of your nine
+ <br />
+ lives; that I mean to make bold withal, and as you
+ <br />
+ shall use me hereafter, drybeat the rest of the
+ <br />
+ eight. Will you pluck your sword out of his pitcher
+ <br />
+ by the ears? make haste, lest mine be about your
+ <br />
+ ears ere it be out.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>I am for you.
+ <br />
+ </p>
+ <p>Drawing</p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Gentle Mercutio, put thy rapier up.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Come, sir, your passado.
+ <br />
+ </p>
+ <p>They fight</p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Draw, Benvolio; beat down their weapons.
+ <br />
+ Gentlemen, for shame, forbear this outrage!
+ <br />
+ Tybalt, Mercutio, the prince expressly hath
+ <br />
+ Forbidden bandying in Verona streets:
+ <br />
+ Hold, Tybalt! good Mercutio!
+ <br />
+ </p>
+ <p>TYBALT under ROMEO's arm stabs MERCUTIO, and flies with his
+ followers
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>I am hurt.
+ <br />
+ A plague o' both your houses! I am sped.
+ <br />
+ Is he gone, and hath nothing?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>What, art thou hurt?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Ay, ay, a scratch, a scratch; marry, 'tis enough.
+ <br />
+ Where is my page? Go, villain, fetch a surgeon.
+ <br />
+ </p>
+ <p>Exit Page</p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Courage, man; the hurt cannot be much.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>No, 'tis not so deep as a well, nor so wide as a
+ <br />
+ church-door; but 'tis enough,'twill serve: ask for
+ <br />
+ me to-morrow, and you shall find me a grave man. I
+ <br />
+ am peppered, I warrant, for this world. A plague o'
+ <br />
+ both your houses! 'Zounds, a dog, a rat, a mouse, a
+ <br />
+ cat, to scratch a man to death! a braggart, a
+ <br />
+ rogue, a villain, that fights by the book of
+ <br />
+ arithmetic! Why the devil came you between us? I
+ <br />
+ was hurt under your arm.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>I thought all for the best.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MERCUTIO</strong>
+ </p>
+
+ <p>Help me into some house, Benvolio,
+ <br />
+ Or I shall faint. A plague o' both your houses!
+ <br />
+ They have made worms' meat of me: I have it,
+ <br />
+ And soundly too: your houses!
+ <br />
+ </p>
+ <p>Exeunt MERCUTIO and BENVOLIO</p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>This gentleman, the prince's near ally,
+ <br />
+ My very friend, hath got his mortal hurt
+ <br />
+ In my behalf; my reputation stain'd
+ <br />
+ With Tybalt's slander,—Tybalt, that an hour
+ <br />
+ Hath been my kinsman! O sweet Juliet,
+ <br />
+ Thy beauty hath made me effeminate
+ <br />
+ And in my temper soften'd valour's steel!
+ <br />
+ </p>
+ <p>Re-enter BENVOLIO</p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>O Romeo, Romeo, brave Mercutio's dead!
+ <br />
+ That gallant spirit hath aspired the clouds,
+ <br />
+ Which too untimely here did scorn the earth.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>This day's black fate on more days doth depend;
+ <br />
+ This but begins the woe, others must end.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Here comes the furious Tybalt back again.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>Alive, in triumph! and Mercutio slain!
+ <br />
+ Away to heaven, respective lenity,
+ <br />
+ And fire-eyed fury be my conduct now!
+ <br />
+ </p>
+ <p>Re-enter TYBALT</p>
+ <p>Now, Tybalt, take the villain back again,
+ <br />
+ That late thou gavest me; for Mercutio's soul
+ <br />
+ Is but a little way above our heads,
+ <br />
+ Staying for thine to keep him company:
+ <br />
+ Either thou, or I, or both, must go with him.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>TYBALT</strong>
+ </p>
+
+ <p>Thou, wretched boy, that didst consort him here,
+ <br />
+ Shalt with him hence.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>This shall determine that.
+ <br />
+ </p>
+ <p>They fight; TYBALT falls</p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Romeo, away, be gone!
+ <br />
+ The citizens are up, and Tybalt slain.
+ <br />
+ Stand not amazed: the prince will doom thee death,
+ <br />
+ If thou art taken: hence, be gone, away!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>ROMEO</strong>
+ </p>
+
+ <p>O, I am fortune's fool!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Why dost thou stay?
+ <br />
+ </p>
+ <p>Exit ROMEO</p>
+ <p>Enter Citizens, &amp; c</p>
+
+
+ <p>
+ <strong>First Citizen</strong>
+ </p>
+
+ <p>Which way ran he that kill'd Mercutio?
+ <br />
+ Tybalt, that murderer, which way ran he?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>There lies that Tybalt.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>First Citizen</strong>
+ </p>
+
+ <p>Up, sir, go with me;
+ <br />
+ I charge thee in the princes name, obey.
+ <br />
+ </p>
+ <p>Enter Prince, attended; MONTAGUE, CAPULET, their Wives, and
+ others
+ </p>
+
+
+ <p>
+ <strong>PRINCE</strong>
+ </p>
+
+ <p>Where are the vile beginners of this fray?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>O noble prince, I can discover all
+ <br />
+ The unlucky manage of this fatal brawl:
+ <br />
+ There lies the man, slain by young Romeo,
+ <br />
+ That slew thy kinsman, brave Mercutio.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>LADY CAPULET</strong>
+ </p>
+
+ <p>Tybalt, my cousin! O my brother's child!
+ <br />
+ O prince! O cousin! husband! O, the blood is spilt
+ <br />
+ O my dear kinsman! Prince, as thou art true,
+ <br />
+ For blood of ours, shed blood of Montague.
+ <br />
+ O cousin, cousin!
+ <br />
+ </p>
+
+
+ <p>
+ <strong>PRINCE</strong>
+ </p>
+
+ <p>Benvolio, who began this bloody fray?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>BENVOLIO</strong>
+ </p>
+
+ <p>Tybalt, here slain, whom Romeo's hand did slay;
+ <br />
+ Romeo that spoke him fair, bade him bethink
+ <br />
+ How nice the quarrel was, and urged withal
+ <br />
+ Your high displeasure: all this uttered
+ <br />
+ With gentle breath, calm look, knees humbly bow'd,
+ <br />
+ Could not take truce with the unruly spleen
+ <br />
+ Of Tybalt deaf to peace, but that he tilts
+ <br />
+ With piercing steel at bold Mercutio's breast,
+ <br />
+ Who all as hot, turns deadly point to point,
+ <br />
+ And, with a martial scorn, with one hand beats
+ <br />
+ Cold death aside, and with the other sends
+ <br />
+ It back to Tybalt, whose dexterity,
+ <br />
+ Retorts it: Romeo he cries aloud,
+ <br />
+ 'Hold, friends! friends, part!' and, swifter than
+ <br />
+ his tongue,
+ <br />
+ His agile arm beats down their fatal points,
+ <br />
+ And 'twixt them rushes; underneath whose arm
+ <br />
+ An envious thrust from Tybalt hit the life
+ <br />
+ Of stout Mercutio, and then Tybalt fled;
+ <br />
+ But by and by comes back to Romeo,
+ <br />
+ Who had but newly entertain'd revenge,
+ <br />
+ And to 't they go like lightning, for, ere I
+ <br />
+ Could draw to part them, was stout Tybalt slain.
+ <br />
+ And, as he fell, did Romeo turn and fly.
+ <br />
+ This is the truth, or let Benvolio die.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>LADY CAPULET</strong>
+ </p>
+
+ <p>He is a kinsman to the Montague;
+ <br />
+ Affection makes him false; he speaks not true:
+ <br />
+ Some twenty of them fought in this black strife,
+ <br />
+ And all those twenty could but kill one life.
+ <br />
+ I beg for justice, which thou, prince, must give;
+ <br />
+ Romeo slew Tybalt, Romeo must not live.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>PRINCE</strong>
+ </p>
+
+ <p>Romeo slew him, he slew Mercutio;
+ <br />
+ Who now the price of his dear blood doth owe?
+ <br />
+ </p>
+
+
+ <p>
+ <strong>MONTAGUE</strong>
+ </p>
+
+ <p>Not Romeo, prince, he was Mercutio's friend;
+ <br />
+ His fault concludes but what the law should end,
+ <br />
+ The life of Tybalt.
+ <br />
+ </p>
+
+
+ <p>
+ <strong>PRINCE</strong>
+ </p>
+
+ <p>And for that offence
+ <br />
+ Immediately we do exile him hence:
+ <br />
+ I have an interest in your hate's proceeding,
+ <br />
+ My blood for your rude brawls doth lie a-bleeding;
+ <br />
+ But I'll amerce you with so strong a fine
+ <br />
+ That you shall all repent the loss of mine:
+ <br />
+ I will be deaf to pleading and excuses;
+ <br />
+ Nor tears nor prayers shall purchase out abuses:
+ <br />
+ Therefore use none: let Romeo hence in haste,
+ <br />
+ Else, when he's found, that hour is his last.
+ <br />
+ Bear hence this body and attend our will:
+ <br />
+ Mercy but murders, pardoning those that kill.
+ <br />
+ </p>
+ <p>Exeunt</p>
+
+
+ </div>
+</div>
+
+
+
diff --git a/vendor/mikespub/php-epub-meta/test/data/metadata.opf b/vendor/mikespub/php-epub-meta/test/data/metadata.opf
new file mode 100644
index 000000000..dc2f6e011
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/metadata.opf
@@ -0,0 +1,35 @@
+<?xml version='1.0' encoding='utf-8'?>
+<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="uuid_id" version="2.0">
+ <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
+ <dc:identifier opf:scheme="calibre" id="calibre_id">17</dc:identifier>
+ <dc:identifier opf:scheme="uuid" id="uuid_id">d74fec58-06bc-4ba8-b8b4-24a91a58e6f9</dc:identifier>
+ <dc:title>Alice's Adventures in Wonderland</dc:title>
+ <dc:creator opf:file-as="Carroll, Lewis" opf:role="aut">Lewis Carroll</dc:creator>
+ <dc:contributor opf:file-as="calibre" opf:role="bkp">calibre (7.6.0) [https://calibre-ebook.com]</dc:contributor>
+ <dc:date>1897-04-10T23:00:00+00:00</dc:date>
+ <dc:description>&lt;p class="description"&gt;Alice's Adventures in Wonderland (1865) is a novel written by English author Charles Lutwidge Dodgson, better known under the pseudonym Lewis Carroll. It tells the story of a girl named Alice who falls down a rabbit-hole into a fantasy world populated by peculiar and anthropomorphic creatures.&lt;br&gt;The tale is filled with allusions to Dodgson's friends (and enemies), and to the lessons that British schoolchildren were expected to memorize. The tale plays with logic in ways that have made the story of lasting popularity with adults as well as children. It is considered to be one of the most characteristic examples of the genre of literary nonsense, and its narrative course and structure has been enormously influential, mainly in the fantasy genre.&lt;/p&gt;
+
+Alice's Adventures in Wonderland (1865) is a novel written by English author Charles Lutwidge Dodgson, better known under the pseudonym Lewis Carroll. It tells the story of a girl named Alice who falls down a rabbit-hole into a fantasy world populated by peculiar and anthropomorphic creatures.
+The tale is filled with allusions to Dodgson's friends (and enemies), and to the lessons that British schoolchildren were expected to memorize. The tale plays with logic in ways that have made the story of lasting popularity with adults as well as children. It is considered to be one of the most characteristic examples of the genre of literary nonsense, and its narrative course and structure has been enormously influential, mainly in the fantasy genre.</dc:description>
+ <dc:publisher>Macmillan and Co. London</dc:publisher>
+ <dc:language>eng</dc:language>
+ <dc:subject>Fantasy</dc:subject>
+ <dc:subject>Juvenile</dc:subject>
+ <dc:subject>Fiction</dc:subject>
+ <meta name="calibre:link_maps" content="{&quot;authors&quot;: {&quot;Lewis Carroll&quot;: &quot;http://www.wikidata.org/entity/Q38082&quot;}}"/>
+ <meta name="calibre:rating" content="4"/>
+ <meta name="calibre:timestamp" content="2012-04-11T12:12:09+00:00"/>
+ <meta name="calibre:title_sort" content="Alice's Adventures in Wonderland"/>
+ <meta name="calibre:user_metadata:#type1" content="{&quot;table&quot;: &quot;custom_column_3&quot;, &quot;column&quot;: &quot;value&quot;, &quot;datatype&quot;: &quot;text&quot;, &quot;is_multiple&quot;: null, &quot;kind&quot;: &quot;field&quot;, &quot;name&quot;: &quot;Type1&quot;, &quot;search_terms&quot;: [&quot;#type1&quot;], &quot;label&quot;: &quot;type1&quot;, &quot;colnum&quot;: 3, &quot;display&quot;: {&quot;use_decorations&quot;: 0}, &quot;is_custom&quot;: true, &quot;is_category&quot;: true, &quot;link_column&quot;: &quot;value&quot;, &quot;category_sort&quot;: &quot;value&quot;, &quot;is_csp&quot;: false, &quot;is_editable&quot;: true, &quot;rec_index&quot;: 22, &quot;#value#&quot;: &quot;text&quot;, &quot;#extra#&quot;: null, &quot;is_multiple2&quot;: {}}"/>
+ <meta name="calibre:user_metadata:#type2" content="{&quot;table&quot;: &quot;custom_column_2&quot;, &quot;column&quot;: &quot;value&quot;, &quot;datatype&quot;: &quot;text&quot;, &quot;is_multiple&quot;: &quot;|&quot;, &quot;kind&quot;: &quot;field&quot;, &quot;name&quot;: &quot;Type2&quot;, &quot;search_terms&quot;: [&quot;#type2&quot;], &quot;label&quot;: &quot;type2&quot;, &quot;colnum&quot;: 2, &quot;display&quot;: {&quot;is_names&quot;: false}, &quot;is_custom&quot;: true, &quot;is_category&quot;: true, &quot;link_column&quot;: &quot;value&quot;, &quot;category_sort&quot;: &quot;value&quot;, &quot;is_csp&quot;: false, &quot;is_editable&quot;: true, &quot;rec_index&quot;: 23, &quot;#value#&quot;: [&quot;tag1&quot;, &quot;tag2&quot;], &quot;#extra#&quot;: null, &quot;is_multiple2&quot;: {&quot;cache_to_list&quot;: &quot;|&quot;, &quot;ui_to_list&quot;: &quot;,&quot;, &quot;list_to_ui&quot;: &quot;, &quot;}}"/>
+ <meta name="calibre:user_metadata:#type4" content="{&quot;table&quot;: &quot;custom_column_1&quot;, &quot;column&quot;: &quot;value&quot;, &quot;datatype&quot;: &quot;series&quot;, &quot;is_multiple&quot;: null, &quot;kind&quot;: &quot;field&quot;, &quot;name&quot;: &quot;Type4&quot;, &quot;search_terms&quot;: [&quot;#type4&quot;], &quot;label&quot;: &quot;type4&quot;, &quot;colnum&quot;: 1, &quot;display&quot;: {}, &quot;is_custom&quot;: true, &quot;is_category&quot;: true, &quot;link_column&quot;: &quot;value&quot;, &quot;category_sort&quot;: &quot;value&quot;, &quot;is_csp&quot;: false, &quot;is_editable&quot;: true, &quot;rec_index&quot;: 24, &quot;#value#&quot;: &quot;SeriesLike&quot;, &quot;#extra#&quot;: 1.0, &quot;is_multiple2&quot;: {}}"/>
+ <meta name="calibre:annotation" content="{&quot;format&quot;: &quot;EPUB&quot;, &quot;user_type&quot;: &quot;local&quot;, &quot;user&quot;: &quot;viewer&quot;, &quot;annotation&quot;: {&quot;title&quot;: &quot;About #1&quot;, &quot;pos_type&quot;: &quot;epubcfi&quot;, &quot;pos&quot;: &quot;epubcfi(/6/2/4/2/6/2:38)&quot;, &quot;timestamp&quot;: &quot;2024-03-11T11:54:35.128396+00:00&quot;, &quot;type&quot;: &quot;bookmark&quot;}}"/>
+ <meta name="calibre:annotation" content="{&quot;format&quot;: &quot;EPUB&quot;, &quot;user_type&quot;: &quot;local&quot;, &quot;user&quot;: &quot;viewer&quot;, &quot;annotation&quot;: {&quot;end_cfi&quot;: &quot;/2/4/2/2/6/1:24&quot;, &quot;highlighted_text&quot;: &quot;Charles Lutwidge Dodgson&quot;, &quot;notes&quot;: &quot;Full author name&quot;, &quot;spine_index&quot;: 2, &quot;spine_name&quot;: &quot;OPS/about.xml&quot;, &quot;start_cfi&quot;: &quot;/2/4/2/2/6/1:0&quot;, &quot;style&quot;: {&quot;kind&quot;: &quot;color&quot;, &quot;type&quot;: &quot;builtin&quot;, &quot;which&quot;: &quot;yellow&quot;}, &quot;timestamp&quot;: &quot;2024-03-11T11:53:55.583Z&quot;, &quot;toc_family_titles&quot;: [&quot;About&quot;], &quot;type&quot;: &quot;highlight&quot;, &quot;uuid&quot;: &quot;5HHGuoCOtpA-umaIbBuc0Q&quot;}}"/>
+ <meta name="calibre:annotation" content="{&quot;format&quot;: &quot;EPUB&quot;, &quot;user_type&quot;: &quot;local&quot;, &quot;user&quot;: &quot;viewer&quot;, &quot;annotation&quot;: {&quot;end_cfi&quot;: &quot;/2/4/2/2[chapter_458]/4/2/1:5&quot;, &quot;highlighted_text&quot;: &quot;Alice&quot;, &quot;notes&quot;: &quot;Protagonist&quot;, &quot;spine_index&quot;: 3, &quot;spine_name&quot;: &quot;OPS/main0.xml&quot;, &quot;start_cfi&quot;: &quot;/2/4/2/2[chapter_458]/4/2/1:0&quot;, &quot;style&quot;: {&quot;kind&quot;: &quot;color&quot;, &quot;type&quot;: &quot;builtin&quot;, &quot;which&quot;: &quot;yellow&quot;}, &quot;timestamp&quot;: &quot;2024-03-11T11:56:52.891Z&quot;, &quot;toc_family_titles&quot;: [&quot;Chapter 1 - Down the Rabbit Hole&quot;], &quot;type&quot;: &quot;highlight&quot;, &quot;uuid&quot;: &quot;KFGNXVB2Heb53ghsAjVqvQ&quot;}}"/>
+ <meta name="calibre:annotation" content="{&quot;format&quot;: &quot;EPUB&quot;, &quot;user_type&quot;: &quot;local&quot;, &quot;user&quot;: &quot;viewer&quot;, &quot;annotation&quot;: {&quot;end_cfi&quot;: &quot;/2/4/2/2/6/1:106&quot;, &quot;highlighted_text&quot;: &quot;Lewis Carroll&quot;, &quot;spine_index&quot;: 2, &quot;spine_name&quot;: &quot;OPS/about.xml&quot;, &quot;start_cfi&quot;: &quot;/2/4/2/2/6/1:93&quot;, &quot;style&quot;: {&quot;kind&quot;: &quot;color&quot;, &quot;type&quot;: &quot;builtin&quot;, &quot;which&quot;: &quot;yellow&quot;}, &quot;timestamp&quot;: &quot;2024-03-11T11:55:32.734Z&quot;, &quot;toc_family_titles&quot;: [&quot;About&quot;], &quot;type&quot;: &quot;highlight&quot;, &quot;uuid&quot;: &quot;iuGTy-WIXWDinBuszppGwA&quot;}}"/>
+ <meta name="calibre:annotation" content="{&quot;format&quot;: &quot;EPUB&quot;, &quot;user_type&quot;: &quot;web&quot;, &quot;user&quot;: &quot;*&quot;, &quot;annotation&quot;: {&quot;type&quot;: &quot;highlight&quot;, &quot;timestamp&quot;: &quot;2024-03-11T16:24:14.624Z&quot;, &quot;uuid&quot;: &quot;1ZUnS8Bf4uZGH0hS9JOKGQ&quot;, &quot;highlighted_text&quot;: &quot;About Carroll&quot;, &quot;start_cfi&quot;: &quot;/2/4/2/2/2/1:0&quot;, &quot;end_cfi&quot;: &quot;/2/4/2/2/2/1:13&quot;, &quot;style&quot;: {&quot;type&quot;: &quot;builtin&quot;, &quot;kind&quot;: &quot;color&quot;, &quot;which&quot;: &quot;yellow&quot;}, &quot;spine_name&quot;: &quot;OPS/about.xml&quot;, &quot;spine_index&quot;: 2, &quot;notes&quot;: &quot;About note&quot;, &quot;toc_family_titles&quot;: [&quot;About&quot;]}}"/>
+ </metadata>
+ <guide>
+ <reference type="cover" title="Cover" href="cover.jpg"/>
+ </guide>
+</package>
diff --git a/vendor/mikespub/php-epub-meta/test/data/nav-non-text_img_title.epub b/vendor/mikespub/php-epub-meta/test/data/nav-non-text_img_title.epub
new file mode 100644
index 000000000..0670367e3
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/nav-non-text_img_title.epub
Binary files differ
diff --git a/vendor/mikespub/php-epub-meta/test/data/test.epub b/vendor/mikespub/php-epub-meta/test/data/test.epub
new file mode 100644
index 000000000..85d60aece
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/test.epub
Binary files differ
diff --git a/vendor/mikespub/php-epub-meta/test/data/test.jpg b/vendor/mikespub/php-epub-meta/test/data/test.jpg
new file mode 100644
index 000000000..4ca4a685c
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/data/test.jpg
Binary files differ
diff --git a/vendor/mikespub/php-epub-meta/test/epubTest.php b/vendor/mikespub/php-epub-meta/test/epubTest.php
new file mode 100644
index 000000000..5056fc260
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/epubTest.php
@@ -0,0 +1,807 @@
+<?php
+
+use PHPUnit\Framework\TestCase;
+use SebLucas\EPubMeta\Contents\NavPoint as TocNavPoint;
+use SebLucas\EPubMeta\EPub;
+use SebLucas\EPubMeta\Data\Item as DataItem;
+use SebLucas\EPubMeta\Tools\ZipEdit;
+
+/**
+ * Test for EPUB library
+ *
+ * Source: https://github.com/splitbrain/php-epub-meta
+ * @author Andreas Gohr <andi@splitbrain.org> © 2012
+ * @author Simon Schrape <simon@epubli.com> © 2015
+ */
+class EPubTest extends TestCase
+{
+ public const TEST_EPUB = __DIR__ . '/data/test.epub';
+ public const TEST_EPUB_COPY = __DIR__ . '/data/test.copy.epub';
+ public const TEST_EPUB_COVER = __DIR__ . '/data/test.cover.epub';
+ public const TEST_IMAGE = __DIR__ . '/data/test.jpg';
+ public const EMPTY_ZIP = __DIR__ . '/data/empty.zip';
+ public const BROKEN_ZIP = __DIR__ . '/data/broken.zip';
+ public const MARKUP_XML_1 = __DIR__ . '/data/markup.1.xml';
+ public const MARKUP_XML_2 = __DIR__ . '/data/markup.2.xml';
+ public const MARKUP_XML_3 = __DIR__ . '/data/markup.3.xml';
+ public const MARKUP_XML_4 = __DIR__ . '/data/markup.4.xml';
+ public const MARKUP_XML_5 = __DIR__ . '/data/markup.5.xml';
+
+ protected EPub $epub;
+
+ protected function setUp(): void
+ {
+ // sometime I might have accidentally broken the test file
+ if (filesize(static::TEST_EPUB) != 768780) {
+ die('test.epub has wrong size, make sure it\'s unmodified');
+ }
+
+ // we work on a copy to test saving
+ if (!copy(static::TEST_EPUB, static::TEST_EPUB_COPY)) {
+ die('failed to create copy of the test book');
+ }
+
+ // @see https://github.com/sebastianbergmann/phpunit/issues/5062#issuecomment-1416362657
+ set_error_handler(
+ static function (int $errno, string $errstr) {
+ throw new \Exception($errstr, $errno);
+ },
+ E_ALL
+ );
+
+ $this->epub = new Epub(static::TEST_EPUB_COPY);
+ }
+
+ protected function tearDown(): void
+ {
+ restore_error_handler();
+
+ unlink(static::TEST_EPUB_COPY);
+ }
+
+ public function testGetZipEntries(): void
+ {
+ $entries = $this->epub->getZipEntries();
+ $this->assertCount(49, $entries);
+ $this->assertArrayHasKey(EPub::METADATA_FILE, $entries);
+ $this->assertEquals(250, $entries[EPub::METADATA_FILE]['size']);
+
+ $count = $this->epub->getImageCount();
+ $this->assertEquals(3, $count);
+
+ $coverpath = $this->epub->getCoverPath();
+ $this->assertEquals('images/cover.png', $coverpath);
+
+ $size = $this->epub->getComponentSize($coverpath);
+ $this->assertEquals(657911, $size);
+ }
+
+ public function testLoadNonZip(): void
+ {
+ //$this->expectException(Exception::class);
+ //$this->expectExceptionMessage('Failed to read EPUB file. Not a zip archive.');
+ //$this->expectExceptionMessage('Failed to read epub file');
+ $this->expectException(ValueError::class);
+ $this->expectExceptionMessage('Invalid or uninitialized Zip object');
+ new Epub(static::TEST_IMAGE);
+ }
+
+ public function testLoadBrokenZip(): void
+ {
+ //$this->expectException(Exception::class);
+ //$this->expectExceptionMessage('Failed to read EPUB file. Zip archive inconsistent.');
+ //$this->expectExceptionMessage('Unable to find metadata.xml');
+ $this->expectException(ValueError::class);
+ $this->expectExceptionMessage('Invalid or uninitialized Zip object');
+ new Epub(static::BROKEN_ZIP);
+ }
+
+ public function testLoadMissingFile(): void
+ {
+ $this->expectException(Exception::class);
+ //$this->expectExceptionMessage('Failed to read EPUB file. No such file.');
+ $this->expectExceptionMessage('Epub file does not exist!');
+ new Epub('/a/file/that/is/not_there.epub');
+ }
+
+ /**
+ * We cannot expect a more specific exception message. ZipArchive::open returns 28
+ * which is not known as an error code.
+ */
+ public function testLoadDirectory(): void
+ {
+ $this->expectException(Exception::class);
+ //$this->expectExceptionMessage('Failed to read EPUB file.');
+ $this->expectExceptionMessage('Epub file does not exist!');
+ new Epub(__DIR__);
+ }
+
+ public function testLoadEmptyZip(): void
+ {
+ $this->expectException(Exception::class);
+ //$this->expectExceptionMessage('Failed to read from EPUB container: META-INF/container.xml');
+ //$this->expectExceptionMessage('Failed to read epub file');
+ $this->expectExceptionMessage('Unable to find ' . EPub::METADATA_FILE);
+ new Epub(static::EMPTY_ZIP);
+ }
+
+ public function testFilename(): void
+ {
+ $this->assertEquals(static::TEST_EPUB_COPY, $this->epub->file());
+ }
+
+ public function testAuthors(): void
+ {
+ // read curent value
+ $this->assertEquals(['Shakespeare, William' => 'William Shakespeare'], $this->epub->getAuthors());
+
+ // remove value with string
+ $this->epub->setAuthors('');
+ $this->assertEquals([], $this->epub->getAuthors());
+
+ // set single value by String
+ $this->epub->setAuthors('John Doe');
+ $this->assertEquals(['John Doe' => 'John Doe'], $this->epub->getAuthors());
+
+ // set single value by indexed array
+ $this->epub->setAuthors(['John Doe']);
+ $this->assertEquals(['John Doe' => 'John Doe'], $this->epub->getAuthors());
+
+ // remove value with array
+ $this->epub->setAuthors([]);
+ $this->assertEquals([], $this->epub->getAuthors());
+
+ // set single value by associative array
+ $this->epub->setAuthors(['Doe, John' => 'John Doe']);
+ $this->assertEquals(['Doe, John' => 'John Doe'], $this->epub->getAuthors());
+
+ // set multi value by string
+ $this->epub->setAuthors('John Doe, Jane Smith');
+ $this->assertEquals(['John Doe' => 'John Doe', 'Jane Smith' => 'Jane Smith'], $this->epub->getAuthors());
+
+ // set multi value by indexed array
+ $this->epub->setAuthors(['John Doe', 'Jane Smith']);
+ $this->assertEquals(['John Doe' => 'John Doe', 'Jane Smith' => 'Jane Smith'], $this->epub->getAuthors());
+
+ // set multi value by associative array
+ $this->epub->setAuthors(['Doe, John' => 'John Doe', 'Smith, Jane' => 'Jane Smith']);
+ $this->assertEquals(['Doe, John' => 'John Doe', 'Smith, Jane' => 'Jane Smith'], $this->epub->getAuthors());
+
+ // check escaping
+ $this->epub->setAuthors(['Doe, John&nbsp;' => 'John Doe&nbsp;']);
+ $this->assertEquals(['Doe, John&nbsp;' => 'John Doe&nbsp;'], $this->epub->getAuthors());
+ }
+
+ public function testTitle(): void
+ {
+ // get current value
+ $this->assertEquals('Romeo and Juliet', $this->epub->getTitle());
+
+ // set new value
+ $this->epub->setTitle('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getTitle());
+
+ // delete current value
+ $this->epub->setTitle('');
+ $this->assertEquals('', $this->epub->getTitle());
+
+ // check escaping
+ $this->epub->setTitle('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getTitle());
+ }
+
+ public function testLanguage(): void
+ {
+ // get current value
+ $this->assertEquals('en', $this->epub->getLanguage());
+
+ // set new value
+ $this->epub->setLanguage('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getLanguage());
+
+ // delete current value
+ $this->epub->setLanguage('');
+ $this->assertEquals('', $this->epub->getLanguage());
+
+ // check escaping
+ $this->epub->setLanguage('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getLanguage());
+ }
+
+ public function testPublisher(): void
+ {
+ // get current value
+ $this->assertEquals('Feedbooks', $this->epub->getPublisher());
+
+ // set new value
+ $this->epub->setPublisher('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getPublisher());
+
+ // delete current value
+ $this->epub->setPublisher('');
+ $this->assertEquals('', $this->epub->getPublisher());
+
+ // check escaping
+ $this->epub->setPublisher('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getPublisher());
+ }
+
+ public function testCopyright(): void
+ {
+ // get current value
+ $this->assertEquals('', $this->epub->getCopyright());
+
+ // set new value
+ $this->epub->setCopyright('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getCopyright());
+
+ // delete current value
+ $this->epub->setCopyright('');
+ $this->assertEquals('', $this->epub->getCopyright());
+
+ // check escaping
+ $this->epub->setCopyright('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getCopyright());
+ }
+
+ public function testDescription(): void
+ {
+ // get current value
+ $this->assertStringStartsWith('Romeo and Juliet is a tragic play written', $this->epub->getDescription());
+
+ // set new value
+ $this->epub->setDescription('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getDescription());
+
+ // delete current value
+ $this->epub->setDescription('');
+ $this->assertEquals('', $this->epub->getDescription());
+
+ // check escaping
+ $this->epub->setDescription('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getDescription());
+ }
+
+ public function testUniqueIdentifier(): void
+ {
+ // get current value
+ $this->assertEquals('urn:uuid:7d38d098-4234-11e1-97b6-001cc0a62c0b', $this->epub->getUniqueIdentifier());
+
+ // set new value
+ $this->epub->setUniqueIdentifier('134htb34tp089h1b');
+ $this->assertEquals('134htb34tp089h1b', $this->epub->getUniqueIdentifier());
+ // this should have affected the same node that is found when looking for UUID/URN scheme
+ $this->assertEquals('134htb34tp089h1b', $this->epub->getUuid());
+ }
+
+ public function testUuid(): void
+ {
+ // get current value
+ $this->assertEquals('urn:uuid:7d38d098-4234-11e1-97b6-001cc0a62c0b', $this->epub->getUuid());
+
+ // set new value
+ $this->epub->setUuid('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getUuid());
+
+ // delete current value
+ $this->epub->setUuid('');
+ $this->assertEquals('', $this->epub->getUuid());
+
+ // check escaping
+ $this->epub->setUuid('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getUuid());
+ }
+
+ public function testUri(): void
+ {
+ // get current value
+ $this->assertEquals('http://www.feedbooks.com/book/2936', $this->epub->getUri());
+
+ // set new value
+ $this->epub->setUri('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getUri());
+
+ // delete current value
+ $this->epub->setUri('');
+ $this->assertEquals('', $this->epub->getUri());
+
+ // check escaping
+ $this->epub->setUri('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getUri());
+ }
+
+ public function testIsbn(): void
+ {
+ // get current value
+ $this->assertEquals('', $this->epub->getIsbn());
+
+ // set new value
+ $this->epub->setIsbn('Foo Bar');
+ $this->assertEquals('Foo Bar', $this->epub->getIsbn());
+
+ // delete current value
+ $this->epub->setIsbn('');
+ $this->assertEquals('', $this->epub->getIsbn());
+
+ // check escaping
+ $this->epub->setIsbn('Foo&nbsp;Bar');
+ $this->assertEquals('Foo&nbsp;Bar', $this->epub->getIsbn());
+ }
+
+ public function testSubject(): void
+ {
+ // get current values
+ $this->assertEquals(['Fiction', 'Drama', 'Romance'], $this->epub->getSubjects());
+
+ // delete current values with String
+ $this->epub->setSubjects('');
+ $this->assertEquals([], $this->epub->getSubjects());
+
+ // set new values with String
+ $this->epub->setSubjects('Fiction, Drama, Romance');
+ $this->assertEquals(['Fiction', 'Drama', 'Romance'], $this->epub->getSubjects());
+
+ // delete current values with Array
+ $this->epub->setSubjects([]);
+ $this->assertEquals([], $this->epub->getSubjects());
+
+ // set new values with array
+ $this->epub->setSubjects(['Fiction', 'Drama', 'Romance']);
+ $this->assertEquals(['Fiction', 'Drama', 'Romance'], $this->epub->getSubjects());
+
+ // check escaping
+ $this->epub->setSubjects(['Fiction', 'Drama&nbsp;', 'Romance']);
+ $this->assertEquals(['Fiction', 'Drama&nbsp;', 'Romance'], $this->epub->getSubjects());
+ }
+
+ public function testCover(): void
+ {
+ // we work on a copy to test saving
+ $this->assertTrue(copy(static::TEST_EPUB, static::TEST_EPUB_COVER));
+
+ // use the ZipEdit class here
+ //$epub = new EPub(static::TEST_EPUB_COVER, ZipEdit::class);
+ $epub = new EPub(static::TEST_EPUB_COVER);
+
+ // read current cover
+ $cover = $epub->getCover();
+ $this->assertEquals(657911, strlen($cover));
+
+ // change cover and save
+ $epub->setCover(static::TEST_IMAGE, 'image/jpeg');
+ //$epub->save();
+
+ // open epub again
+ //$epub = new EPub(static::TEST_EPUB_COVER);
+
+ // read recently changed cover
+ $cover = $epub->getCover();
+ $this->assertEquals(filesize(static::TEST_IMAGE), strlen($cover));
+
+ // delete cover
+ $epub->clearCover();
+ $cover = $epub->getCover();
+ $this->assertNull($cover);
+
+ $epub->close();
+
+ unlink(static::TEST_EPUB_COVER);
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testTitlePage()
+ {
+ // we work on a copy to test saving
+ $this->assertTrue(copy(static::TEST_EPUB, static::TEST_EPUB_COVER));
+
+ // use the ZipEdit class here
+ //$epub = new EPub(static::TEST_EPUB_COVER, ZipEdit::class);
+ $epub = new EPub(static::TEST_EPUB_COVER);
+
+ // add title page and save
+ $epub->addCoverImageTitlePage();
+ //$epub->save();
+
+ // open epub again
+ //$epub = new EPub(static::TEST_EPUB_COVER);
+
+ // read recently added title page
+ $spine = $epub->getSpine();
+ $titlePage = $spine->first();
+ $this->assertEquals(EPub::TITLE_PAGE_ID . '.xhtml', $titlePage->getHref());
+ $this->assertEquals(EPub::TITLE_PAGE_ID, $titlePage->getId());
+ $this->assertEquals('application/xhtml+xml', (string) $titlePage->getMediaType());
+
+ // We expect an empty string since there is only an image but no text on that page.
+ $this->assertEmpty(trim($titlePage->getContents()));
+
+ unlink(static::TEST_EPUB_COVER);
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testCalibreAnnotations()
+ {
+ $epub = new Epub(static::TEST_EPUB);
+ // use metadata from .opf file for tests here - see Alice from mikespub/seblucas-cops
+ $data = file_get_contents(__DIR__ . '/data/metadata.opf');
+ $annotations = $epub->getCalibreAnnotations($data);
+ $this->assertCount(5, $annotations);
+ $expected = [
+ 'format' => 'EPUB',
+ 'user_type' => 'local',
+ 'user' => 'viewer',
+ 'annotation' => [
+ 'title' => 'About #1',
+ 'pos_type' => 'epubcfi',
+ 'pos' => 'epubcfi(/6/2/4/2/6/2:38)',
+ 'timestamp' => '2024-03-11T11:54:35.128396+00:00',
+ 'type' => 'bookmark',
+ ],
+ ];
+ $this->assertEquals($expected, $annotations[0]);
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testCalibreBookmarks()
+ {
+ $epub = new Epub(static::TEST_EPUB);
+ // use calibre_bookmarks.txt for tests here - see Alice from mikespub/seblucas-cops
+ $data = file_get_contents(__DIR__ . '/data/calibre_bookmarks.txt');
+ $bookmarks = $epub->getCalibreBookmarks($data);
+ $this->assertCount(5, $bookmarks);
+ $expected = [
+ 'title' => 'About #1',
+ 'pos_type' => 'epubcfi',
+ 'pos' => 'epubcfi(/6/2/4/2/6/2:38)',
+ 'timestamp' => '2024-03-11T11:54:35.128396+00:00',
+ 'type' => 'bookmark',
+ ];
+ $this->assertEquals($expected, $bookmarks[0]);
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testManifest()
+ {
+ $manifest = $this->epub->getManifest();
+ $this->assertCount(41, $manifest);
+
+ $this->assertEquals('cover', $manifest->first()->getId());
+ $this->assertEquals(DataItem::XHTML, $manifest->current()->getMediaType());
+ $manifest->next();
+ $this->assertEquals('title.xml', $manifest->current()->getHref());
+ $this->assertEquals('ncx', $manifest->last()->getId());
+
+ $this->assertSame($manifest['cover'], $manifest->first());
+ $this->assertSame($manifest['ncx'], $manifest->last());
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testSpine()
+ {
+ $spine = $this->epub->getSpine();
+ $this->assertCount(31, $spine);
+
+ $this->assertEquals('cover', $spine->first()->getId());
+ $this->assertEquals(DataItem::XHTML, $spine->current()->getMediaType());
+ $spine->next();
+ $this->assertEquals('title.xml', $spine->current()->getHref());
+ $this->assertEquals('feedbooks', $spine->last()->getId());
+
+ $this->assertEquals('fb.ncx', $spine->getTocItem()->getHref());
+
+ $this->assertSame($spine[0], $spine->first());
+ $this->assertSame($spine[30], $spine->last());
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testToc()
+ {
+ $this->assertEquals(2, $this->epub->getEpubVersion());
+
+ $toc = $this->epub->getToc();
+ $this->assertEquals('Romeo and Juliet', $toc->getDocTitle());
+ $this->assertEquals('Shakespeare, William', $toc->getDocAuthor());
+ $navMap = $toc->getNavMap();
+ $this->assertEquals(8, $navMap->count());
+
+ $navPoint = $navMap->first();
+ /** @var TocNavPoint $navPoint */
+ $this->assertEquals('level1-titlepage', $navPoint->getId());
+ $this->assertEquals('titlepage', $navPoint->getClass());
+ $this->assertEquals('1', $navPoint->getPlayOrder());
+ $this->assertEquals('Title', $navPoint->getNavLabel());
+ $this->assertEquals('title.xml', $navPoint->getContentSource());
+ $this->assertCount(0, $navPoint->getChildren());
+
+ $navMap->next();
+ $navMap->next();
+ $navPoint = $navMap->current();
+ /** @var TocNavPoint $navPoint */
+ $this->assertEquals('sec77303', $navPoint->getId());
+ $this->assertEquals('section', $navPoint->getClass());
+ $this->assertEquals('3', $navPoint->getPlayOrder());
+ $this->assertEquals('Act I', $navPoint->getNavLabel());
+ $this->assertEquals('main0.xml', $navPoint->getContentSource());
+ $this->assertCount(6, $navPoint->getChildren());
+ $this->assertEquals('Prologue', $navPoint->getChildren()->first()->getNavLabel());
+ $this->assertEquals('SCENE V. A hall in Capulet\'s house.', $navPoint->getChildren()->last()->getNavLabel());
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testNav()
+ {
+ $test_epub3 = __DIR__ . '/data/nav-non-text_img_title.epub';
+ $test_epub3_copy = __DIR__ . '/data/nav-non-text_img_title.copy.epub';
+
+ // sometime I might have accidentally broken the test file
+ $this->assertEquals(239564, filesize($test_epub3));
+
+ // we work on a copy to test saving
+ $this->assertTrue(copy($test_epub3, $test_epub3_copy));
+
+ $epub = new EPub($test_epub3_copy);
+ $this->assertEquals(3, $epub->getEpubVersion());
+
+ $toc = $epub->getNav();
+ $this->assertEquals('nav-non-text_img_title', $toc->getDocTitle());
+ $this->assertEquals('Ivan Herman', $toc->getDocAuthor());
+ $navMap = $toc->getNavMap();
+ $this->assertEquals(2, $navMap->count());
+
+ $navPoint = $navMap->first();
+ /** @var TocNavPoint $navPoint */
+ $this->assertEquals('', $navPoint->getId());
+ $this->assertEquals('h1', $navPoint->getClass());
+ $this->assertEquals('1', $navPoint->getPlayOrder());
+ $this->assertEquals('Start page', $navPoint->getNavLabel());
+ $this->assertEquals('content_001.xhtml', $navPoint->getContentSource());
+ $this->assertCount(0, $navPoint->getChildren());
+
+ $navMap->next();
+ $navPoint = $navMap->current();
+ /** @var TocNavPoint $navPoint */
+ $this->assertEquals('', $navPoint->getId());
+ $this->assertEquals('h1', $navPoint->getClass());
+ $this->assertEquals('2', $navPoint->getPlayOrder());
+ $this->assertEquals('Description of the Abbey of Sénanque', $navPoint->getNavLabel());
+ $this->assertEquals('senanque.xhtml', $navPoint->getContentSource());
+ $this->assertCount(0, $navPoint->getChildren());
+ //$this->assertEquals('Prologue', $navPoint->getChildren()->first()->getNavLabel());
+ //$this->assertEquals('SCENE V. A hall in Capulet\'s house.', $navPoint->getChildren()->last()->getNavLabel());
+
+ unlink($test_epub3_copy);
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testNavTree()
+ {
+ $test_epub3 = __DIR__ . '/data/eng3.epub';
+ $test_epub3_copy = __DIR__ . '/data/eng3.copy.epub';
+
+ // sometime I might have accidentally broken the test file
+ $this->assertEquals(53216, filesize($test_epub3));
+
+ // we work on a copy to test saving
+ $this->assertTrue(copy($test_epub3, $test_epub3_copy));
+
+ $epub = new EPub($test_epub3_copy);
+
+ $toc = $epub->getNav();
+ $this->assertEquals('Calibre Quick Start Guide', $toc->getDocTitle());
+ $this->assertEquals('John Schember', $toc->getDocAuthor());
+ $navMap = $toc->getNavMap();
+ $this->assertEquals(7, $navMap->count());
+ $this->assertCount(1, $navMap->findNavPointsForFile('text/introduction.xhtml'));
+ $this->assertCount(0, $navMap->findNavPointsForFile('oops/are_we_lost?.xhtml'));
+
+ $navPoint = $navMap->first();
+ /** @var TocNavPoint $navPoint */
+ $this->assertEquals('', $navPoint->getId());
+ $this->assertEquals('h1', $navPoint->getClass());
+ $this->assertEquals('1', $navPoint->getPlayOrder());
+ $this->assertEquals('Calibre Quick Start Guide', $navPoint->getNavLabel());
+ $this->assertEquals('text/internal_titlepage.xhtml', $navPoint->getContentSource());
+ $this->assertCount(0, $navPoint->getChildren());
+
+ $navMap->seek(5);
+ $navPoint = $navMap->current();
+ /** @var TocNavPoint $navPoint */
+ $this->assertEquals('', $navPoint->getId());
+ $this->assertEquals('h1', $navPoint->getClass());
+ $this->assertEquals(6, $navPoint->getPlayOrder());
+ $this->assertEquals('Common Tasks', $navPoint->getNavLabel());
+ $this->assertEquals('text/common_tasks.xhtml', $navPoint->getContentSource());
+ $this->assertCount(6, $navPoint->getChildren());
+ $this->assertEquals('Task 1: Organizing', $navPoint->getChildren()->first()->getNavLabel());
+ $navPoint->getChildren()->next();
+ $childPoint = $navPoint->getChildren()->current();
+ $this->assertEquals('Task 2: Conversion', $childPoint->getNavLabel());
+ $this->assertCount(7, $childPoint->getChildren());
+ $this->assertEquals('Task 6: The e-book viewer', $navPoint->getChildren()->last()->getNavLabel());
+
+ unlink($test_epub3_copy);
+ }
+
+ /**
+ * @dataProvider provideContentsTestParameters
+ * @param string $referenceStart The expected start of the extracted contents.
+ * @param string $referenceEnd The expected end of the extracted contents.
+ * @param int $referenceSize The expected size of the extracted contents.
+ * @param bool $keepMarkup Whether to extract contents with or without HTML markup.
+ * @param float $fraction
+ * @throws Exception
+ * @return void
+ */
+ public function testContents(
+ $referenceStart,
+ $referenceEnd,
+ $referenceSize,
+ $keepMarkup,
+ $fraction
+ ) {
+ $contents = trim($this->epub->getContents($keepMarkup, $fraction));
+ $this->assertStringStartsWith($referenceStart, substr($contents, 0, 100));
+ $this->assertStringEndsWith($referenceEnd, substr($contents, -100));
+ $this->assertEquals($referenceSize, strlen($contents));
+ }
+
+ /**
+ * Summary of provideContentsTestParameters
+ * @return array<mixed>
+ */
+ public static function provideContentsTestParameters()
+ {
+ return [
+ ["Romeo and Juliet\n\nWilliam Shakespeare", "www.feedbooks.com\n\n Food for the mind", 152879, false, 1],
+ ["Romeo and Juliet\n\nWilliam Shakespeare", "seek happy nights to happy days.\n\nExeunt", 24936, false, .2],
+ ["Romeo and Juliet\n\nWilliam Shakespeare", "miss, our toil shall strive to mend.", 3810, false, .1],
+ ];
+ }
+
+ /**
+ * @dataProvider provideItemContentsTestParameters
+ * @param string $referenceStart The expected start of the extracted contents.
+ * @param string $referenceEnd The expected end of the extracted contents.
+ * @param string $spineIndex The spine index of the item to extract contents from.
+ * @param string $fragmentBegin The anchor name (ID) where to start extraction.
+ * @param string $fragmentEnd The anchor name (ID) where to end extraction.
+ * @throws Exception
+ * @return void
+ */
+ public function testItemContents(
+ $referenceStart,
+ $referenceEnd,
+ $spineIndex,
+ $fragmentBegin = null,
+ $fragmentEnd = null
+ ) {
+ $spine = $this->epub->getSpine();
+ $contents = trim($spine[$spineIndex]->getContents($fragmentBegin, $fragmentEnd));
+ $this->assertStringStartsWith($referenceStart, $contents);
+ $this->assertStringEndsWith($referenceEnd, $contents);
+ }
+
+ /**
+ * Summary of provideItemContentsTestParameters
+ * @return array<mixed>
+ */
+ public static function provideItemContentsTestParameters()
+ {
+ return [
+ ['Act I', 'our toil shall strive to mend.', 3],
+ ['SCENE I. Verona. A public place.', "I'll pay that doctrine, or else die in debt.\n\nExeunt", 4],
+ ['Act III', 'Act III', 16, 'section_77331', 'section_77332'],
+ ['Act III', 'Act III', 16, null, 'section_77332'],
+ ['SCENE I. A public place.', "pardoning those that kill.\n\nExeunt", 16, 'section_77332'],
+ ];
+ }
+
+ public function testItemContentsStartFragmentException(): void
+ {
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('Begin of fragment not found:');
+ $spine = $this->epub->getSpine();
+ $spine[3]->getContents('NonExistingElement');
+ }
+
+ public function testItemContentsEndFragmentException(): void
+ {
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('End of fragment not found:');
+ $spine = $this->epub->getSpine();
+ $spine[3]->getContents(null, 'NonExistingElement');
+ }
+
+ /**
+ * @dataProvider provideItemContentsMarkupTestParameters
+ * @param string $referenceFile
+ * @param string $spineIndex
+ * @param string $fragmentBegin
+ * @param string $fragmentEnd
+ * @throws Exception
+ * @return void
+ */
+ public function testItemContentsMarkup($referenceFile, $spineIndex, $fragmentBegin = null, $fragmentEnd = null)
+ {
+ $spine = $this->epub->getSpine();
+ $contents = $spine[$spineIndex]->getContents($fragmentBegin, $fragmentEnd, true);
+ $contents = preg_replace('/\s+/m', ' ', $contents);
+ $extracted = new DOMDocument();
+ $extracted->loadXML($contents);
+ $extstring = $extracted->saveXML($extracted->documentElement);
+ $extstring = preg_replace('/\s*([<>])\s*/m', '$1', $extstring);
+ $reference = new DOMDocument();
+ $contents = file_get_contents($referenceFile);
+ $contents = preg_replace('/\s+/m', ' ', $contents);
+ $reference->loadXML($contents);
+ $refstring = $reference->saveXML($reference->documentElement);
+ $refstring = preg_replace('/\s*([<>])\s*/m', '$1', $refstring);
+ $this->assertEquals($refstring, $extstring);
+ //$this->assertEqualXMLStructure($reference->documentElement, $extracted->documentElement);
+ }
+
+ /**
+ * Summary of provideItemContentsMarkupTestParameters
+ * @return array<mixed>
+ */
+ public static function provideItemContentsMarkupTestParameters()
+ {
+ return [
+ [static::MARKUP_XML_1, 3],
+ [static::MARKUP_XML_2, 4],
+ [static::MARKUP_XML_3, 16, 'section_77331', 'section_77332'],
+ [static::MARKUP_XML_4, 16, null, 'section_77332'],
+ [static::MARKUP_XML_5, 16, 'section_77332'],
+ ];
+ }
+
+ /**
+ * @throws Exception
+ * @return void
+ */
+ public function testItemDataSize()
+ {
+ $item = $this->epub->getSpine()[0];
+ $size = $item->getSize();
+ $data = $item->getData();
+
+ $this->assertEquals(strlen($data), $size);
+ }
+
+ /**
+ * Summary of testZipEdit
+ * @return void
+ */
+ public function testZipEdit()
+ {
+ ZipEdit::copyTest(static::TEST_EPUB_COPY, static::TEST_EPUB_COVER);
+ $epub = new EPub(static::TEST_EPUB_COVER);
+ $oldManifest = $this->epub->getManifest();
+ $newManifest = $epub->getManifest();
+ $this->assertEquals($oldManifest, $newManifest);
+ }
+}
diff --git a/vendor/mikespub/php-epub-meta/test/monocleTest.php b/vendor/mikespub/php-epub-meta/test/monocleTest.php
new file mode 100644
index 000000000..20cc5a6c5
--- /dev/null
+++ b/vendor/mikespub/php-epub-meta/test/monocleTest.php
@@ -0,0 +1,159 @@
+<?php
+
+use PHPUnit\Framework\TestCase;
+use SebLucas\EPubMeta\EPub;
+
+/**
+ * Test for EPUB methods used by Monocle in COPS
+ *
+ * Source: https://github.com/mikespub-org/seblucas
+ */
+class MonocleTest extends TestCase
+{
+ public const TEST_EPUB = __DIR__ . '/data/eng.epub';
+ public const TEST_EPUB_COPY = __DIR__ . '/data/eng.copy.epub';
+ public const TEST_CONTENTS = __DIR__ . '/data/eng.contents.json';
+ public const TEST_COMPONENTS = __DIR__ . '/data/eng.components.json';
+ public const TEST_EPUB3 = __DIR__ . '/data/eng3.epub';
+
+ private static EPub $book;
+
+ public static function setUpBeforeClass(): void
+ {
+ // sometime I might have accidentally broken the test file
+ if (filesize(static::TEST_EPUB) != 22664) {
+ die('test.epub has wrong size, make sure it\'s unmodified');
+ }
+
+ // we work on a copy to test saving
+ if (!copy(static::TEST_EPUB, static::TEST_EPUB_COPY)) {
+ die('failed to create copy of the test book');
+ }
+
+ // @see https://github.com/sebastianbergmann/phpunit/issues/5062#issuecomment-1416362657
+ set_error_handler(
+ static function (int $errno, string $errstr) {
+ throw new \Exception($errstr, $errno);
+ },
+ E_ALL
+ );
+
+ self::$book = new Epub(static::TEST_EPUB_COPY);
+ self::$book->initSpineComponent();
+ }
+
+ public static function tearDownAfterClass(): void
+ {
+ restore_error_handler();
+
+ unlink(static::TEST_EPUB_COPY);
+ }
+
+ public function testComponents(): void
+ {
+ $data = self::$book->components();
+ $contents = file_get_contents(static::TEST_COMPONENTS);
+ $check = json_decode($contents, true);
+ $encoder = $this->provideEncodeReplace();
+ $check = str_replace($encoder[0], $encoder[1], $check);
+ $this->assertEquals($check, $data);
+ }
+
+ public function testContents(): void
+ {
+ $data = self::$book->contents();
+ $contents = file_get_contents(static::TEST_CONTENTS);
+ $check = json_decode($contents, true);
+ $encoder = $this->provideEncodeReplace();
+ foreach (array_keys($check) as $idx) {
+ $check[$idx] = $this->encodeItem($check[$idx], $encoder);
+ }
+ $this->assertEquals($check, $data);
+ }
+
+ /**
+ * Summary of testComponent
+ * @param string $component
+ * @return void
+ */
+ public function testComponent($component = 'text/titlepage.xhtml')
+ {
+ $data = self::$book->component($component);
+ $check = 641;
+ $this->assertEquals($check, strlen($data));
+ }
+
+ /**
+ * Summary of testGetComponentName
+ * @param string $component
+ * @param string $element
+ * @return void
+ */
+ public function testGetComponentName($component = 'text/titlepage.xhtml', $element = '../images/cover.jpg')
+ {
+ $data = self::$book->getComponentName($component, $element);
+ $check = 'images~SLASH~cover.jpg';
+ $this->assertEquals($check, $data);
+ }
+
+ /**
+ * Summary of testComponentContentType
+ * @param string $component
+ * @return void
+ */
+ public function testComponentContentType($component = 'text/titlepage.xhtml')
+ {
+ $data = self::$book->componentContentType($component);
+ $check = 'application/xhtml+xml';
+ $this->assertEquals($check, $data);
+ }
+
+ public function testContentsEpub3(): void
+ {
+ $epub = new EPub(__DIR__ . '/data/eng3.epub');
+ $epub->initSpineComponent();
+ $data = $epub->contents();
+ $contents = file_get_contents(static::TEST_CONTENTS);
+ $check = json_decode($contents, true);
+ $encoder = $this->provideEncodeReplace();
+ foreach (array_keys($check) as $idx) {
+ $check[$idx] = $this->encodeItem($check[$idx], $encoder);
+ }
+ $this->assertEquals($check, $data);
+ }
+
+ /**
+ * Summary of encodeItem
+ * @param array<mixed> $item
+ * @param array<mixed> $encoder
+ * @return array<mixed>
+ */
+ protected function encodeItem($item, $encoder)
+ {
+ $item['src'] = str_replace($encoder[0], $encoder[1], $item['src']);
+ if (!empty($item['children'])) {
+ foreach (array_keys($item['children']) as $idx) {
+ $item['children'][$idx] = $this->encodeItem($item['children'][$idx], $encoder);
+ }
+ }
+ return $item;
+ }
+
+ /**
+ * Summary of provideEncodeReplace
+ * @return array<mixed>
+ */
+ public function provideEncodeReplace()
+ {
+ return EPub::$encodeNameReplace;
+ }
+
+ /**
+ * Summary of provideDecodeReplace
+ * @return array<mixed>
+ */
+ public function provideDecodeReplace()
+ {
+ return EPub::$decodeNameReplace;
+ }
+}