Add tests for CFI round-tripping

This commit is contained in:
Kovid Goyal 2020-04-05 09:31:44 +05:30
parent 8648e3ff2f
commit 7c9cafc63f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 64 additions and 10 deletions

View File

@ -136,7 +136,9 @@ def encode(doc, node, offset, tail): # {{{
# Handle the offset, if any
if node.nodeType is Node.ELEMENT_NODE:
if jstype(offset) is 'number':
node = node.childNodes.item(offset)
q = node.childNodes.item(offset)
if q and q.nodeType is Node.ELEMENT_NODE:
node = q
elif Node.TEXT_NODE <= node.nodeType <= Node.ENTITY_NODE:
offset = offset or 0
while True:
@ -212,7 +214,7 @@ def decode(cfi, doc): # {{{
cfi = cfi.substr(r[0].length)
break
index |= 1 # Increment index by 1 if it is even
if child.nodeType is 1:
if child.nodeType is Node.ELEMENT_NODE:
index += 1
if index is target:
cfi = cfi.substr(r[0].length)
@ -276,8 +278,6 @@ def decode(cfi, doc): # {{{
# TODO: Handle text assertion
# Find the text node that contains the offset
if node and node.parentNode:
node.parentNode.normalize()
if offset is not None:
while True:
l = node.nodeValue.length

View File

@ -2,11 +2,46 @@
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
from read_book.cfi import escape_for_cfi, unescape_from_cfi
from testing import test, assert_equal
from elementmaker import E
from read_book.cfi import encode, decode, escape_for_cfi, unescape_from_cfi
from testing import assert_equal, test
@test
def cfi_escaping():
t = 'a^!,1'
assert_equal(t, unescape_from_cfi(escape_for_cfi(t)))
@test
def cfi_roundtripping():
idc = 0
def nid():
nonlocal idc
idc += 1
return idc + ''
document.body.appendChild(E.p('abc'))
p = document.body.firstChild
path_to_p = '/2/4/2'
assert_equal(encode(document, p), path_to_p)
assert_equal(decode(path_to_p), {'node': p})
assert_equal(encode(document, p.firstChild), f'{path_to_p}/1:0')
assert_equal(decode(f'{path_to_p}/1:0'), {'node': p.firstChild, 'offset': 0})
assert_equal(encode(document, p.firstChild, 1), f'{path_to_p}/1:1')
assert_equal(decode(f'{path_to_p}/1:1'), {'node': p.firstChild, 'offset': 1})
p.appendChild(document.createTextNode('def'))
assert_equal(encode(document, p.firstChild, 5), f'{path_to_p}/1:5')
assert_equal(p.childNodes.length, 2)
assert_equal(encode(document, p.lastChild, 1), f'{path_to_p}/1:4')
assert_equal(decode(f'{path_to_p}/1:5'), {'node': p.lastChild, 'offset': 2})
assert_equal(decode(f'{path_to_p}/1:1'), {'node': p.firstChild, 'offset': 1})
p.appendChild(E.span('123', id=nid()))
p.appendChild(document.createTextNode('456'))
assert_equal(encode(document, p.lastChild, 1), f'{path_to_p}/1:7')
assert_equal(decode(f'{path_to_p}/1:7'), {'node': p.lastChild, 'offset': 1})

View File

@ -25,8 +25,8 @@ def get_traceback(lines):
lines = traceback.format_exception()
last_line = lines[-1]
final_lines = v'[]'
pat = /at assert_\w+ \(/
for line in lines:
pat = /at assert_[0-9a-zA-Z_]+ \(/
for line in lines[:-1]:
if pat.test(line):
break
final_lines.push(line)

View File

@ -14,10 +14,21 @@ def raise_fail(preamble, msg, call_site):
raise AssertionError(preamble + msg)
def repr_of(a):
if not a:
return a
q = a.outerHTML
if q:
return q.split('>')[0] + '>'
return a
def assert_equal(a, b, msg, call_site=None):
def fail():
p = f'{a} != {b}'
ra = repr_of(a)
rb = repr_of(b)
p = f'{ra} != {rb}'
raise_fail(p, msg, call_site)
atype = jstype(a)
@ -31,10 +42,18 @@ def assert_equal(a, b, msg, call_site=None):
if not a.__eq__(b):
fail()
return
if a.isSameNode:
if not a.isSameNode(b):
fail()
return
if b.__eq__:
if not b.__eq__(a):
fail()
return
if b.isSameNode:
if not b.isSameNode(a):
fail()
return
if a.length? or b.length?:
if a.length is not b.length:
fail()
@ -48,7 +67,7 @@ def assert_equal(a, b, msg, call_site=None):
for key in Object.keys(b):
assert_equal(a[key], b[key])
if a is not b:
if atype is not 'object' and btype is not 'object':
fail()