Add tests for EPUB CFI

This commit is contained in:
John Factotum
2022-10-19 17:03:49 +00:00
committed by GitHub
parent 8ca6bd5f29
commit 3ac917c706
5 changed files with 209 additions and 3 deletions
+202
View File
@@ -0,0 +1,202 @@
import * as CFI from '../epubcfi.js'
const parser = new DOMParser()
const XML = str => parser.parseFromString(str, 'application/xml')
const XHTML = str => parser.parseFromString(str, 'application/xhtml+xml')
{
// example from EPUB CFI spec
const opf = XML(`<?xml version="1.0"?>
<package version="2.0"
unique-identifier="bookid"
xmlns="http://www.idpf.org/2007/opf"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:opf="http://www.idpf.org/2007/opf">
<metadata>
<dc:title>…</dc:title>
<dc:identifier id="bookid">…</dc:identifier>
<dc:creator>…</dc:creator>
<dc:language>en</dc:language>
</metadata>
<manifest>
<item id="toc"
properties="nav"
href="toc.xhtml"
media-type="application/xhtml+xml"/>
<item id="titlepage"
href="titlepage.xhtml"
media-type="application/xhtml+xml"/>
<item id="chapter01"
href="chapter01.xhtml"
media-type="application/xhtml+xml"/>
<item id="chapter02"
href="chapter02.xhtml"
media-type="application/xhtml+xml"/>
<item id="chapter03"
href="chapter03.xhtml"
media-type="application/xhtml+xml"/>
<item id="chapter04"
href="chapter04.xhtml"
media-type="application/xhtml+xml"/>
</manifest>
<spine>
<itemref id="titleref" idref="titlepage"/>
<itemref id="chap01ref" idref="chapter01"/>
<itemref id="chap02ref" idref="chapter02"/>
<itemref id="chap03ref" idref="chapter03"/>
<itemref id="chap04ref" idref="chapter04"/>
</spine>
</package>`)
const page = XHTML(`<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>…</title>
</head>
<body id="body01">
<p>…</p>
<p>…</p>
<p>…</p>
<p>…</p>
<p id="para05">xxx<em>yyy</em>0123456789</p>
<p>…</p>
<p>…</p>
<img id="svgimg" src="foo.svg" alt="…"/>
<p>…</p>
<p>…</p>
</body>
</html>`)
// the exact same page with some text nodes removed, CDATA sections added,
// and characters changed to entities
const page2 = XHTML(`<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>…</title>
</head>
<body id="body01">
<p>…</p><p>…</p><p>…</p><p>…</p>
<p id="para05">xxx<em>yyy</em><![CDATA[0123]]>45<![CDATA[67]]>&#56;&#57;</p>
<p>…</p>
<p>…</p>
<img id="svgimg" src="foo.svg" alt="…"/>
<p>…</p>
<p>…</p>
</body>
</html>`)
const a = opf.getElementById('chap01ref')
const b = CFI.toElement(opf, CFI.parse('/6/4[chap01ref]')[0])
const c = CFI.toElement(opf, CFI.parse('/6/4')[0])
console.assert(a === b)
console.assert(a === c)
const test = page => {
for (const cfi of [
'/4[body01]/10[para05]/3:10',
'/4[body01]/16[svgimg]',
'/4[body01]/10[para05]/1:0',
'/4[body01]/10[para05]/2/1:0',
'/4[body01]/10[para05]/2/1:3',
]) {
const range = CFI.toRange(page, CFI.parse(cfi))
const a = CFI.fromRange(range)
const b = `epubcfi(${cfi})`
console.assert(a === b, `expected ${b}, got ${a}`)
}
for (let i = 0; i < 10; i++) {
const cfi = `/4/10,/3:${i},/3:${i+1}`
const range = CFI.toRange(page, CFI.parse(cfi))
const n = `${i}`
console.assert(range.toString() === n, `expted ${n}, got ${range}`)
}
}
test(page)
test(page2)
}
{
// special characters in ID assertions
const opf = XML(`<?xml version="1.0"?>
<package version="2.0"
unique-identifier="bookid"
xmlns="http://www.idpf.org/2007/opf"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:opf="http://www.idpf.org/2007/opf">
<metadata></metadata>
<manifest></manifest>
<spine>
<itemref id="titleref" idref="titlepage"/>
<itemref id="chap0]!/1ref^" idref="chapter01"/>
<itemref id="chap02ref" idref="chapter02"/>
<itemref id="chap03ref" idref="chapter03"/>
<itemref id="chap04ref" idref="chapter04"/>
</spine>
</package>`)
const a = opf.getElementById('chap0]!/1ref^')
const b = CFI.toElement(opf, CFI.parse('/6/4[chap0^]!/1ref^^]')[0])
console.assert(a === b)
const page = XHTML(`<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>…</title>
</head>
<body id="body0]!/1^">
<p>…</p>
<p>…</p>
<p>…</p>
<p>…</p>
<p id="para]/0,/5">xxx<em>yyy</em>0123456789</p>
<p>…</p>
<p>…</p>
<img id="s][vgimg" src="foo.svg" alt="…"/>
<p>…</p>
<p>…</p>
</body>
</html>`)
for (const cfi of [
'/4[body0^]!/1^^]/10[para^]/0^,/5]/3:10',
'/4[body0^]!/1^^]/16[s^]^[vgimg]',
'/4[body0^]!/1^^]/10[para^]/0^,/5]/1:0',
'/4[body0^]!/1^^]/10[para^]/0^,/5]/2/1:0',
'/4[body0^]!/1^^]/10[para^]/0^,/5]/2/1:3',
]) {
const range = CFI.toRange(page, CFI.parse(cfi))
const a = CFI.fromRange(range)
const b = `epubcfi(${cfi})`
console.assert(a === b, `expected ${b}, got ${a}`)
}
for (let i = 0; i < 10; i++) {
const cfi = `/4[body0^]!/1^^]/10[para^]/0^,^/5],/3:${i},/3:${i+1}`
const range = CFI.toRange(page, CFI.parse(cfi))
const n = `${i}`
console.assert(range.toString() === n, `expted ${n}, got ${range}`)
}
}
{
for (const [a, b, c] of [
['/6/4!/10', '/6/4!/10', 0],
['/6/4!/2/3:0', '/6/4!/2', 1],
['/6/4!/2/4/6/8/10/3:0', '/6/4!/4', -1],
[
'/6/4[chap0^]!/1ref^^]!/4[body01^^]/10[para^]^,05^^]',
'/6/4!/4/10',
0,
],
[
'/6/4[chap0^]!/1ref^^]!/4[body01^^],/10[para^]^,05^^],/15:10[foo^]]',
'/6/4!/4/12',
-1,
],
]) {
const x = CFI.compare(a, b)
console.assert(x === c, `compare ${a} and ${b}, expected ${c}, got ${x}`)
}
}