2012-12-21 08:51:59 +01:00
|
|
|
# coding: utf-8
|
|
|
|
|
2019-12-25 22:36:26 +01:00
|
|
|
import os
|
|
|
|
import tempfile
|
2019-12-24 10:14:48 +01:00
|
|
|
|
2019-12-25 22:36:26 +01:00
|
|
|
from anki import Collection as aopen
|
2020-02-20 03:48:46 +01:00
|
|
|
from anki.lang import without_unicode_isolation
|
2020-02-16 12:07:40 +01:00
|
|
|
from anki.rsbackend import StringsGroup
|
2019-12-25 22:36:26 +01:00
|
|
|
from anki.stdmodels import addBasicModel, models
|
2019-12-24 10:14:48 +01:00
|
|
|
from anki.utils import isWin
|
2014-06-03 10:38:47 +02:00
|
|
|
from tests.shared import assertException, getEmptyCol
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2019-12-25 05:18:34 +01:00
|
|
|
|
2017-10-05 06:14:56 +02:00
|
|
|
def test_create_open():
|
2014-04-21 23:04:46 +02:00
|
|
|
(fd, path) = tempfile.mkstemp(suffix=".anki2", prefix="test_attachNew")
|
2012-12-21 08:51:59 +01:00
|
|
|
try:
|
2014-04-21 23:04:46 +02:00
|
|
|
os.close(fd)
|
2012-12-21 08:51:59 +01:00
|
|
|
os.unlink(path)
|
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
deck = aopen(path)
|
|
|
|
# for open()
|
|
|
|
newPath = deck.path
|
|
|
|
deck.close()
|
|
|
|
newMod = deck.mod
|
|
|
|
del deck
|
|
|
|
|
2017-10-05 06:14:56 +02:00
|
|
|
# reopen
|
2012-12-21 08:51:59 +01:00
|
|
|
deck = aopen(newPath)
|
|
|
|
assert deck.mod == newMod
|
|
|
|
deck.close()
|
|
|
|
|
|
|
|
# non-writeable dir
|
2019-12-24 10:14:48 +01:00
|
|
|
if isWin:
|
|
|
|
dir = "c:\root.anki2"
|
|
|
|
else:
|
|
|
|
dir = "/attachroot.anki2"
|
2019-12-25 05:18:34 +01:00
|
|
|
assertException(Exception, lambda: aopen(dir))
|
2012-12-21 08:51:59 +01:00
|
|
|
# reuse tmp file from before, test non-writeable file
|
|
|
|
os.chmod(newPath, 0)
|
2019-12-25 05:18:34 +01:00
|
|
|
assertException(Exception, lambda: aopen(newPath))
|
2016-05-12 06:45:35 +02:00
|
|
|
os.chmod(newPath, 0o666)
|
2012-12-21 08:51:59 +01:00
|
|
|
os.unlink(newPath)
|
|
|
|
|
2019-12-25 05:18:34 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
def test_noteAddDelete():
|
2014-06-03 10:38:47 +02:00
|
|
|
deck = getEmptyCol()
|
2012-12-21 08:51:59 +01:00
|
|
|
# add a note
|
|
|
|
f = deck.newNote()
|
2019-12-25 05:18:34 +01:00
|
|
|
f["Front"] = "one"
|
|
|
|
f["Back"] = "two"
|
2012-12-21 08:51:59 +01:00
|
|
|
n = deck.addNote(f)
|
|
|
|
assert n == 1
|
|
|
|
# test multiple cards - add another template
|
2019-12-25 05:18:34 +01:00
|
|
|
m = deck.models.current()
|
|
|
|
mm = deck.models
|
2012-12-21 08:51:59 +01:00
|
|
|
t = mm.newTemplate("Reverse")
|
2019-12-25 05:18:34 +01:00
|
|
|
t["qfmt"] = "{{Back}}"
|
|
|
|
t["afmt"] = "{{Front}}"
|
2012-12-21 08:51:59 +01:00
|
|
|
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
|
2019-12-20 22:25:30 +01:00
|
|
|
mm.save(m, templates=True, updateReqs=False)
|
2012-12-21 08:51:59 +01:00
|
|
|
assert deck.cardCount() == 2
|
|
|
|
# creating new notes should use both cards
|
|
|
|
f = deck.newNote()
|
2019-12-25 05:18:34 +01:00
|
|
|
f["Front"] = "three"
|
|
|
|
f["Back"] = "four"
|
2012-12-21 08:51:59 +01:00
|
|
|
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()
|
2019-12-25 05:18:34 +01:00
|
|
|
f2["Front"] = "one"
|
|
|
|
f2["Back"] = ""
|
2012-12-21 08:51:59 +01:00
|
|
|
assert f2.dupeOrEmpty()
|
|
|
|
# empty first field should not be permitted either
|
2019-12-25 05:18:34 +01:00
|
|
|
f2["Front"] = " "
|
2012-12-21 08:51:59 +01:00
|
|
|
assert f2.dupeOrEmpty()
|
|
|
|
|
2019-12-25 05:18:34 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
def test_fieldChecksum():
|
2014-06-03 10:38:47 +02:00
|
|
|
deck = getEmptyCol()
|
2012-12-21 08:51:59 +01:00
|
|
|
f = deck.newNote()
|
2019-12-25 05:18:34 +01:00
|
|
|
f["Front"] = "new"
|
|
|
|
f["Back"] = "new2"
|
2012-12-21 08:51:59 +01:00
|
|
|
deck.addNote(f)
|
2019-12-25 05:18:34 +01:00
|
|
|
assert deck.db.scalar("select csum from notes") == int("c2a6b03f", 16)
|
2012-12-21 08:51:59 +01:00
|
|
|
# changing the val should change the checksum
|
2019-12-25 05:18:34 +01:00
|
|
|
f["Front"] = "newx"
|
2012-12-21 08:51:59 +01:00
|
|
|
f.flush()
|
2019-12-25 05:18:34 +01:00
|
|
|
assert deck.db.scalar("select csum from notes") == int("302811ae", 16)
|
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
|
|
|
|
def test_addDelTags():
|
2014-06-03 10:38:47 +02:00
|
|
|
deck = getEmptyCol()
|
2012-12-21 08:51:59 +01:00
|
|
|
f = deck.newNote()
|
2019-12-25 05:18:34 +01:00
|
|
|
f["Front"] = "1"
|
2012-12-21 08:51:59 +01:00
|
|
|
deck.addNote(f)
|
|
|
|
f2 = deck.newNote()
|
2019-12-25 05:18:34 +01:00
|
|
|
f2["Front"] = "2"
|
2012-12-21 08:51:59 +01:00
|
|
|
deck.addNote(f2)
|
|
|
|
# adding for a given id
|
|
|
|
deck.tags.bulkAdd([f.id], "foo")
|
2019-12-25 05:18:34 +01:00
|
|
|
f.load()
|
|
|
|
f2.load()
|
2012-12-21 08:51:59 +01:00
|
|
|
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
|
|
|
|
|
2019-12-25 05:18:34 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
def test_timestamps():
|
2014-06-03 10:38:47 +02:00
|
|
|
deck = getEmptyCol()
|
2017-08-15 13:31:58 +02:00
|
|
|
assert len(deck.models.models) == len(models)
|
2012-12-21 08:51:59 +01:00
|
|
|
for i in range(100):
|
|
|
|
addBasicModel(deck)
|
2017-08-15 13:31:58 +02:00
|
|
|
assert len(deck.models.models) == 100 + len(models)
|
2012-12-21 08:51:59 +01:00
|
|
|
|
2019-12-25 05:18:34 +01:00
|
|
|
|
2012-12-21 08:51:59 +01:00
|
|
|
def test_furigana():
|
2014-06-03 10:38:47 +02:00
|
|
|
deck = getEmptyCol()
|
2012-12-21 08:51:59 +01:00
|
|
|
mm = deck.models
|
|
|
|
m = mm.current()
|
|
|
|
# filter should work
|
2019-12-25 05:18:34 +01:00
|
|
|
m["tmpls"][0]["qfmt"] = "{{kana:Front}}"
|
2012-12-21 08:51:59 +01:00
|
|
|
mm.save(m)
|
|
|
|
n = deck.newNote()
|
2019-12-25 05:18:34 +01:00
|
|
|
n["Front"] = "foo[abc]"
|
2012-12-21 08:51:59 +01:00
|
|
|
deck.addNote(n)
|
|
|
|
c = n.cards()[0]
|
|
|
|
assert c.q().endswith("abc")
|
|
|
|
# and should avoid sound
|
2019-12-25 05:18:34 +01:00
|
|
|
n["Front"] = "foo[sound:abc.mp3]"
|
2012-12-21 08:51:59 +01:00
|
|
|
n.flush()
|
2020-01-24 02:06:11 +01:00
|
|
|
assert "anki:play" in c.q(reload=True)
|
2012-12-21 08:51:59 +01:00
|
|
|
# it shouldn't throw an error while people are editing
|
2019-12-25 05:18:34 +01:00
|
|
|
m["tmpls"][0]["qfmt"] = "{{kana:}}"
|
2012-12-21 08:51:59 +01:00
|
|
|
mm.save(m)
|
|
|
|
c.q(reload=True)
|
2020-02-16 12:07:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_translate():
|
|
|
|
d = getEmptyCol()
|
|
|
|
tr = d.backend.translate
|
2020-02-20 03:48:46 +01:00
|
|
|
no_uni = without_unicode_isolation
|
2020-02-16 12:07:40 +01:00
|
|
|
|
2020-02-16 12:40:54 +01:00
|
|
|
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."
|