Anki/pylib/tests/test_collection.py
Damien Elmes 8abb35372a test out the Python Fluent implementation
The parsing step is considerably slower in Python, but if parsing
is moved out of the test function, Python wins at 45ms to Rust's 67ms
on 10,000 rounds, presumably due to the overhead of serializing to
Protobuf. Not enough of a difference to justify the inclusion of extra
dependencies and duplicating the lookup code in any case.
2020-02-17 08:40:17 +10:00

194 lines
5.2 KiB
Python

# coding: utf-8
import os
import tempfile
from anki import Collection as aopen
from anki.rsbackend import StringsGroup
from anki.stdmodels import addBasicModel, models
from anki.utils import isWin
from tests.shared import assertException, getEmptyCol
def test_create_open():
(fd, path) = tempfile.mkstemp(suffix=".anki2", prefix="test_attachNew")
try:
os.close(fd)
os.unlink(path)
except OSError:
pass
deck = aopen(path)
# for open()
newPath = deck.path
deck.close()
newMod = deck.mod
del deck
# reopen
deck = aopen(newPath)
assert deck.mod == newMod
deck.close()
# non-writeable dir
if isWin:
dir = "c:\root.anki2"
else:
dir = "/attachroot.anki2"
assertException(Exception, lambda: aopen(dir))
# reuse tmp file from before, test non-writeable file
os.chmod(newPath, 0)
assertException(Exception, lambda: aopen(newPath))
os.chmod(newPath, 0o666)
os.unlink(newPath)
def test_noteAddDelete():
deck = getEmptyCol()
# add a note
f = deck.newNote()
f["Front"] = "one"
f["Back"] = "two"
n = deck.addNote(f)
assert n == 1
# test multiple cards - add another template
m = deck.models.current()
mm = deck.models
t = mm.newTemplate("Reverse")
t["qfmt"] = "{{Back}}"
t["afmt"] = "{{Front}}"
mm.addTemplate(m, t)
mm.save(m)
# the default save doesn't generate cards
assert deck.cardCount() == 1
# but when templates are edited such as in the card layout screen, it
# should generate cards on close
mm.save(m, templates=True, updateReqs=False)
assert deck.cardCount() == 2
# creating new notes should use both cards
f = deck.newNote()
f["Front"] = "three"
f["Back"] = "four"
n = deck.addNote(f)
assert n == 2
assert deck.cardCount() == 4
# check q/a generation
c0 = f.cards()[0]
assert "three" in c0.q()
# it should not be a duplicate
assert not f.dupeOrEmpty()
# now let's make a duplicate
f2 = deck.newNote()
f2["Front"] = "one"
f2["Back"] = ""
assert f2.dupeOrEmpty()
# empty first field should not be permitted either
f2["Front"] = " "
assert f2.dupeOrEmpty()
def test_fieldChecksum():
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "new"
f["Back"] = "new2"
deck.addNote(f)
assert deck.db.scalar("select csum from notes") == int("c2a6b03f", 16)
# changing the val should change the checksum
f["Front"] = "newx"
f.flush()
assert deck.db.scalar("select csum from notes") == int("302811ae", 16)
def test_addDelTags():
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "1"
deck.addNote(f)
f2 = deck.newNote()
f2["Front"] = "2"
deck.addNote(f2)
# adding for a given id
deck.tags.bulkAdd([f.id], "foo")
f.load()
f2.load()
assert "foo" in f.tags
assert "foo" not in f2.tags
# should be canonified
deck.tags.bulkAdd([f.id], "foo aaa")
f.load()
assert f.tags[0] == "aaa"
assert len(f.tags) == 2
def test_timestamps():
deck = getEmptyCol()
assert len(deck.models.models) == len(models)
for i in range(100):
addBasicModel(deck)
assert len(deck.models.models) == 100 + len(models)
def test_furigana():
deck = getEmptyCol()
mm = deck.models
m = mm.current()
# filter should work
m["tmpls"][0]["qfmt"] = "{{kana:Front}}"
mm.save(m)
n = deck.newNote()
n["Front"] = "foo[abc]"
deck.addNote(n)
c = n.cards()[0]
assert c.q().endswith("abc")
# and should avoid sound
n["Front"] = "foo[sound:abc.mp3]"
n.flush()
assert "anki:play" in c.q(reload=True)
# it shouldn't throw an error while people are editing
m["tmpls"][0]["qfmt"] = "{{kana:}}"
mm.save(m)
c.q(reload=True)
def test_translate():
d = getEmptyCol()
tr = d.backend.translate
# strip off unicode separators
def no_uni(s: str) -> str:
return s.replace("\u2068", "").replace("\u2069", "")
def test_backend():
assert tr(StringsGroup.TEST, "valid-key") == "a valid key"
assert "invalid-key" in tr(StringsGroup.TEST, "invalid-key")
assert no_uni(tr(StringsGroup.TEST, "plural", hats=1)) == "You have 1 hat."
assert no_uni(tr(StringsGroup.TEST, "plural", hats=2)) == "You have 2 hats."
import time
t = time.time()
test_backend()
print(time.time() - t)
from fluent.runtime import FluentBundle, FluentResource
test_path = os.path.join(
os.path.dirname(__file__), "../../rslib/tests/support/test.ftl"
)
def python_render(bundle, key, **kwargs):
try:
return bundle.format_pattern(bundle.get_message(key).value, kwargs)[0]
except:
return f"Missing key: {key}"
def test_python():
bundle = FluentBundle(["en-US"])
bundle.add_resource(FluentResource(open(test_path).read()))
assert python_render(bundle, "valid-key") == "a valid key"
assert "invalid-key" in python_render(bundle, "invalid-key")
assert no_uni(python_render(bundle, "plural", hats=1)) == "You have 1 hat."
assert no_uni(python_render(bundle, "plural", hats=2)) == "You have 2 hats."
t = time.time()
test_python()
print(time.time() - t)