diora-web/tui/tests/test_marks.py

80 lines
3.8 KiB
Python
Raw Permalink Normal View History

"""Anchors the way the web reader writes them: block index plus character offsets into the
block's raw text (whitespace as in the file)."""
from diora_tui import blocks, marks
from diora_tui.blocks import collapse_map, load_flat_book
BODY = (
"<h1>Titel</h1>\n"
"<p>\n Erster Satz mit\n Umbruch. <i>Kursiv</i> Ende.\n</p>\n"
"<p>Zweiter Absatz.</p>"
)
def test_collapse_map():
raw = "\n ab cd \n"
norm_of_raw, raw_of_norm, length = collapse_map(raw)
assert length == 5 and "".join(raw[i] if raw[i] != " " else " " for i in raw_of_norm) == "ab cd"
assert raw_of_norm == [3, 4, 5, 8, 9] # a, b, the first space of the run, c, d
assert norm_of_raw[3] == 0 and norm_of_raw[5] == 2 and norm_of_raw[len(raw)] == 5
def test_anchor_counts_in_raw_text_and_resolves_back(epub):
book = load_flat_book(epub([BODY]))
idx = marks.MarkIndex(book)
para = next(i for i, b in enumerate(book.blocks) if b.text.startswith("Erster"))
text = book.blocks[para].text
assert text == "Erster Satz mit Umbruch. Kursiv Ende."
s = text.index("Satz")
e = text.index("Umbruch") + len("Umbruch")
anchor = idx.anchor((para, s), (para, e))
raw = idx.maps(para).raw
assert raw[anchor["startChar"]:anchor["endChar"]] == "Satz mit\n Umbruch" # raw offsets: whitespace as in the file
assert anchor["startBlockIndex"] == anchor["endBlockIndex"] == para and anchor["type"] == "epub"
assert anchor["quote"] == "Satz mit\n Umbruch" and anchor["chapterSrc"].endswith("c0.xhtml")
spans = idx.spans([{"type": "highlight", "color": "green", "anchor": anchor}])
assert list(spans) == [para] and spans[para][0][:2] == (s, e)
def test_range_over_blocks_and_notes_and_bad_anchors(epub):
book = load_flat_book(epub([BODY]))
idx = marks.MarkIndex(book)
first = next(i for i, b in enumerate(book.blocks) if b.text.startswith("Erster"))
last = first + 1
anchor = idx.anchor((first, 7), (last, 6))
spans = idx.spans([{"type": "highlight", "anchor": anchor}])
assert spans[first][0][:2] == (7, len(book.blocks[first].text)) and spans[last][0][:2] == (0, 6)
note = {"type": "note", "anchor": idx.anchor((first, 0), (first, 6))}
assert idx.spans([note])[first][0][:2] == (0, 6)
junk = [{"anchor": {"startBlockIndex": 9999}}, {"anchor": None}, {"anchor": {"startBlockIndex": "x"}}, {}]
assert idx.spans(junk) == {}
def test_a_footnote_marker_with_spaces_cannot_be_addressed_so_the_quote_is_used(epub):
body = '<p>Vor <a href="#n"><sup> 1 </sup></a>nach dem Marker.</p><p id="n">Fuß</p>'
book = load_flat_book(epub([body]))
idx = marks.MarkIndex(book)
assert idx.maps(0) is None
assert idx.anchor((0, 0), (0, 3)) is None # refused: not exact
spans = idx.spans([{"type": "highlight", "anchor": {"startBlockIndex": 0, "endBlockIndex": 0, "startChar": 3, "endChar": 9, "quote": "nach dem"}}])
t = book.blocks[0].text
assert spans[0][0][:2] == (t.index("nach dem"), t.index("nach dem") + 8)
def test_words():
t = "ab cd e"
assert marks.word_starts(t) == [0, 4, 7]
assert marks.next_word(t, 0) == 4 and marks.next_word(t, 7) is None
assert marks.prev_word(t, 4) == 0 and marks.prev_word(t, 0) is None
assert marks.word_at(t, 2) == (4, 6) # in the gap: the next word
def test_an_old_xpath_anchor_is_found_by_its_quote(epub):
book = load_flat_book(epub([BODY]))
idx = marks.MarkIndex(book)
old = {"type": "note", "anchor": {"type": "epub", "chapterSrc": book.chapter_srcs[0], "startXpath": "/p[1]", "startOffset": 3,
"endXpath": "/p[1]", "endOffset": 8, "quote": "Zweiter Absatz"}}
spans = idx.spans([old])
(bi, [(s, e, _)]), = spans.items()
assert book.blocks[bi].text[s:e] == "Zweiter Absatz"
assert idx.spans([{"anchor": {"type": "epub", "chapterSrc": "elsewhere.xhtml", "quote": "x"}}]) == {}