Merge pull request #691 from Arthur-Milchior/no_single_name_var_in_test

Improve variable names in tests
This commit is contained in:
Damien Elmes 2020-07-17 15:37:22 +10:00 committed by GitHub
commit 7d8818f855
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 1971 additions and 1962 deletions

View file

@ -4,90 +4,91 @@ from tests.shared import getEmptyCol
def test_delete():
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "1"
f["Back"] = "2"
deck.addNote(f)
cid = f.cards()[0].id
deck.reset()
deck.sched.answerCard(deck.sched.getCard(), 2)
deck.remove_cards_and_orphaned_notes([cid])
assert deck.cardCount() == 0
assert deck.noteCount() == 0
assert deck.db.scalar("select count() from notes") == 0
assert deck.db.scalar("select count() from cards") == 0
assert deck.db.scalar("select count() from graves") == 2
col = getEmptyCol()
note = col.newNote()
note["Front"] = "1"
note["Back"] = "2"
col.addNote(note)
cid = note.cards()[0].id
col.reset()
col.sched.answerCard(col.sched.getCard(), 2)
col.remove_cards_and_orphaned_notes([cid])
assert col.cardCount() == 0
assert col.noteCount() == 0
assert col.db.scalar("select count() from notes") == 0
assert col.db.scalar("select count() from cards") == 0
assert col.db.scalar("select count() from graves") == 2
def test_misc():
d = getEmptyCol()
f = d.newNote()
f["Front"] = "1"
f["Back"] = "2"
d.addNote(f)
c = f.cards()[0]
id = d.models.current()["id"]
col = getEmptyCol()
note = col.newNote()
note["Front"] = "1"
note["Back"] = "2"
col.addNote(note)
c = note.cards()[0]
id = col.models.current()["id"]
assert c.template()["ord"] == 0
def test_genrem():
d = getEmptyCol()
f = d.newNote()
f["Front"] = "1"
f["Back"] = ""
d.addNote(f)
assert len(f.cards()) == 1
m = d.models.current()
mm = d.models
col = getEmptyCol()
note = col.newNote()
note["Front"] = "1"
note["Back"] = ""
col.addNote(note)
assert len(note.cards()) == 1
m = col.models.current()
mm = col.models
# adding a new template should automatically create cards
t = mm.newTemplate("rev")
t["qfmt"] = "{{Front}}"
t["afmt"] = ""
mm.addTemplate(m, t)
mm.save(m, templates=True)
assert len(f.cards()) == 2
assert len(note.cards()) == 2
# if the template is changed to remove cards, they'll be removed
t = m["tmpls"][1]
t["qfmt"] = "{{Back}}"
mm.save(m, templates=True)
rep = d.backend.get_empty_cards()
for note in rep.notes:
d.remove_cards_and_orphaned_notes(note.card_ids)
assert len(f.cards()) == 1
rep = col.backend.get_empty_cards()
rep = col.backend.get_empty_cards()
for n in rep.notes:
col.remove_cards_and_orphaned_notes(n.card_ids)
assert len(note.cards()) == 1
# if we add to the note, a card should be automatically generated
f.load()
f["Back"] = "1"
f.flush()
assert len(f.cards()) == 2
note.load()
note["Back"] = "1"
note.flush()
assert len(note.cards()) == 2
def test_gendeck():
d = getEmptyCol()
cloze = d.models.byName("Cloze")
d.models.setCurrent(cloze)
f = d.newNote()
f["Text"] = "{{c1::one}}"
d.addNote(f)
assert d.cardCount() == 1
assert f.cards()[0].did == 1
# set the model to a new default deck
newId = d.decks.id("new")
col = getEmptyCol()
cloze = col.models.byName("Cloze")
col.models.setCurrent(cloze)
note = col.newNote()
note["Text"] = "{{c1::one}}"
col.addNote(note)
assert col.cardCount() == 1
assert note.cards()[0].did == 1
# set the model to a new default col
newId = col.decks.id("new")
cloze["did"] = newId
d.models.save(cloze, updateReqs=False)
# a newly generated card should share the first card's deck
f["Text"] += "{{c2::two}}"
f.flush()
assert f.cards()[1].did == 1
col.models.save(cloze, updateReqs=False)
# a newly generated card should share the first card's col
note["Text"] += "{{c2::two}}"
note.flush()
assert note.cards()[1].did == 1
# and same with multiple cards
f["Text"] += "{{c3::three}}"
f.flush()
assert f.cards()[2].did == 1
# if one of the cards is in a different deck, it should revert to the
note["Text"] += "{{c3::three}}"
note.flush()
assert note.cards()[2].did == 1
# if one of the cards is in a different col, it should revert to the
# model default
c = f.cards()[1]
c = note.cards()[1]
c.did = newId
c.flush()
f["Text"] += "{{c4::four}}"
f.flush()
assert f.cards()[3].did == newId
note["Text"] += "{{c4::four}}"
note.flush()
assert note.cards()[3].did == newId

View file

@ -19,17 +19,17 @@ def test_create_open():
os.unlink(path)
except OSError:
pass
deck = aopen(path)
col = aopen(path)
# for open()
newPath = deck.path
newMod = deck.mod
deck.close()
del deck
newPath = col.path
newMod = col.mod
col.close()
del col
# reopen
deck = aopen(newPath)
assert deck.mod == newMod
deck.close()
col = aopen(newPath)
assert col.mod == newMod
col.close()
# non-writeable dir
if isWin:
@ -45,96 +45,96 @@ def test_create_open():
def test_noteAddDelete():
deck = getEmptyCol()
col = getEmptyCol()
# add a note
f = deck.newNote()
f["Front"] = "one"
f["Back"] = "two"
n = deck.addNote(f)
note = col.newNote()
note["Front"] = "one"
note["Back"] = "two"
n = col.addNote(note)
assert n == 1
# test multiple cards - add another template
m = deck.models.current()
mm = deck.models
m = col.models.current()
mm = col.models
t = mm.newTemplate("Reverse")
t["qfmt"] = "{{Back}}"
t["afmt"] = "{{Front}}"
mm.addTemplate(m, t)
mm.save(m)
assert deck.cardCount() == 2
assert col.cardCount() == 2
# creating new notes should use both cards
f = deck.newNote()
f["Front"] = "three"
f["Back"] = "four"
n = deck.addNote(f)
note = col.newNote()
note["Front"] = "three"
note["Back"] = "four"
n = col.addNote(note)
assert n == 2
assert deck.cardCount() == 4
assert col.cardCount() == 4
# check q/a generation
c0 = f.cards()[0]
c0 = note.cards()[0]
assert "three" in c0.q()
# it should not be a duplicate
assert not f.dupeOrEmpty()
assert not note.dupeOrEmpty()
# now let's make a duplicate
f2 = deck.newNote()
f2["Front"] = "one"
f2["Back"] = ""
assert f2.dupeOrEmpty()
note2 = col.newNote()
note2["Front"] = "one"
note2["Back"] = ""
assert note2.dupeOrEmpty()
# empty first field should not be permitted either
f2["Front"] = " "
assert f2.dupeOrEmpty()
note2["Front"] = " "
assert note2.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)
col = getEmptyCol()
note = col.newNote()
note["Front"] = "new"
note["Back"] = "new2"
col.addNote(note)
assert col.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)
note["Front"] = "newx"
note.flush()
assert col.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)
col = getEmptyCol()
note = col.newNote()
note["Front"] = "1"
col.addNote(note)
note2 = col.newNote()
note2["Front"] = "2"
col.addNote(note2)
# 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
col.tags.bulkAdd([note.id], "foo")
note.load()
note2.load()
assert "foo" in note.tags
assert "foo" not in note2.tags
# should be canonified
deck.tags.bulkAdd([f.id], "foo aaa")
f.load()
assert f.tags[0] == "aaa"
assert len(f.tags) == 2
col.tags.bulkAdd([note.id], "foo aaa")
note.load()
assert note.tags[0] == "aaa"
assert len(note.tags) == 2
def test_timestamps():
deck = getEmptyCol()
assert len(deck.models.all_names_and_ids()) == len(get_stock_notetypes(deck))
col = getEmptyCol()
assert len(col.models.all_names_and_ids()) == len(get_stock_notetypes(col))
for i in range(100):
addBasicModel(deck)
assert len(deck.models.all_names_and_ids()) == 100 + len(get_stock_notetypes(deck))
addBasicModel(col)
assert len(col.models.all_names_and_ids()) == 100 + len(get_stock_notetypes(col))
def test_furigana():
deck = getEmptyCol()
mm = deck.models
col = getEmptyCol()
mm = col.models
m = mm.current()
# filter should work
m["tmpls"][0]["qfmt"] = "{{kana:Front}}"
mm.save(m)
n = deck.newNote()
n = col.newNote()
n["Front"] = "foo[abc]"
deck.addNote(n)
col.addNote(n)
c = n.cards()[0]
assert c.q().endswith("abc")
# and should avoid sound
@ -148,15 +148,15 @@ def test_furigana():
def test_translate():
d = getEmptyCol()
col = getEmptyCol()
no_uni = without_unicode_isolation
assert (
d.tr(TR.CARD_TEMPLATE_RENDERING_FRONT_SIDE_PROBLEM)
col.tr(TR.CARD_TEMPLATE_RENDERING_FRONT_SIDE_PROBLEM)
== "Front template has a problem:"
)
assert no_uni(d.tr(TR.STATISTICS_REVIEWS, reviews=1)) == "1 review"
assert no_uni(d.tr(TR.STATISTICS_REVIEWS, reviews=2)) == "2 reviews"
assert no_uni(col.tr(TR.STATISTICS_REVIEWS, reviews=1)) == "1 review"
assert no_uni(col.tr(TR.STATISTICS_REVIEWS, reviews=2)) == "2 reviews"
def test_db_named_args(capsys):

View file

@ -5,141 +5,141 @@ from tests.shared import assertException, getEmptyCol
def test_basic():
deck = getEmptyCol()
# we start with a standard deck
assert len(deck.decks.all_names_and_ids()) == 1
col = getEmptyCol()
# we start with a standard col
assert len(col.decks.all_names_and_ids()) == 1
# it should have an id of 1
assert deck.decks.name(1)
# create a new deck
parentId = deck.decks.id("new deck")
assert col.decks.name(1)
# create a new col
parentId = col.decks.id("new deck")
assert parentId
assert len(deck.decks.all_names_and_ids()) == 2
assert len(col.decks.all_names_and_ids()) == 2
# should get the same id
assert deck.decks.id("new deck") == parentId
# we start with the default deck selected
assert deck.decks.selected() == 1
assert deck.decks.active() == [1]
# we can select a different deck
deck.decks.select(parentId)
assert deck.decks.selected() == parentId
assert deck.decks.active() == [parentId]
assert col.decks.id("new deck") == parentId
# we start with the default col selected
assert col.decks.selected() == 1
assert col.decks.active() == [1]
# we can select a different col
col.decks.select(parentId)
assert col.decks.selected() == parentId
assert col.decks.active() == [parentId]
# let's create a child
childId = deck.decks.id("new deck::child")
deck.sched.reset()
childId = col.decks.id("new deck::child")
col.sched.reset()
# it should have been added to the active list
assert deck.decks.selected() == parentId
assert deck.decks.active() == [parentId, childId]
assert col.decks.selected() == parentId
assert col.decks.active() == [parentId, childId]
# we can select the child individually too
deck.decks.select(childId)
assert deck.decks.selected() == childId
assert deck.decks.active() == [childId]
col.decks.select(childId)
assert col.decks.selected() == childId
assert col.decks.active() == [childId]
# parents with a different case should be handled correctly
deck.decks.id("ONE")
m = deck.models.current()
m["did"] = deck.decks.id("one::two")
deck.models.save(m, updateReqs=False)
n = deck.newNote()
col.decks.id("ONE")
m = col.models.current()
m["did"] = col.decks.id("one::two")
col.models.save(m, updateReqs=False)
n = col.newNote()
n["Front"] = "abc"
deck.addNote(n)
col.addNote(n)
def test_remove():
deck = getEmptyCol()
# create a new deck, and add a note/card to it
g1 = deck.decks.id("g1")
f = deck.newNote()
f["Front"] = "1"
f.model()["did"] = g1
deck.addNote(f)
c = f.cards()[0]
assert c.did == g1
assert deck.cardCount() == 1
deck.decks.rem(g1)
assert deck.cardCount() == 0
col = getEmptyCol()
# create a new col, and add a note/card to it
deck1 = col.decks.id("deck1")
note = col.newNote()
note["Front"] = "1"
note.model()["did"] = deck1
col.addNote(note)
c = note.cards()[0]
assert c.did == deck1
assert col.cardCount() == 1
col.decks.rem(deck1)
assert col.cardCount() == 0
# if we try to get it, we get the default
assert deck.decks.name(c.did) == "[no deck]"
assert col.decks.name(c.did) == "[no deck]"
def test_rename():
d = getEmptyCol()
id = d.decks.id("hello::world")
col = getEmptyCol()
id = col.decks.id("hello::world")
# should be able to rename into a completely different branch, creating
# parents as necessary
d.decks.rename(d.decks.get(id), "foo::bar")
names = [n.name for n in d.decks.all_names_and_ids()]
col.decks.rename(col.decks.get(id), "foo::bar")
names = [n.name for n in col.decks.all_names_and_ids()]
assert "foo" in names
assert "foo::bar" in names
assert "hello::world" not in names
# create another deck
id = d.decks.id("tmp")
# create another col
id = col.decks.id("tmp")
# automatically adjusted if a duplicate name
d.decks.rename(d.decks.get(id), "FOO")
names = [n.name for n in d.decks.all_names_and_ids()]
col.decks.rename(col.decks.get(id), "FOO")
names = [n.name for n in col.decks.all_names_and_ids()]
assert "FOO+" in names
# when renaming, the children should be renamed too
d.decks.id("one::two::three")
id = d.decks.id("one")
d.decks.rename(d.decks.get(id), "yo")
names = [n.name for n in d.decks.all_names_and_ids()]
col.decks.id("one::two::three")
id = col.decks.id("one")
col.decks.rename(col.decks.get(id), "yo")
names = [n.name for n in col.decks.all_names_and_ids()]
for n in "yo", "yo::two", "yo::two::three":
assert n in names
# over filtered
filteredId = d.decks.newDyn("filtered")
filtered = d.decks.get(filteredId)
childId = d.decks.id("child")
child = d.decks.get(childId)
assertException(DeckRenameError, lambda: d.decks.rename(child, "filtered::child"))
assertException(DeckRenameError, lambda: d.decks.rename(child, "FILTERED::child"))
filteredId = col.decks.newDyn("filtered")
filtered = col.decks.get(filteredId)
childId = col.decks.id("child")
child = col.decks.get(childId)
assertException(DeckRenameError, lambda: col.decks.rename(child, "filtered::child"))
assertException(DeckRenameError, lambda: col.decks.rename(child, "FILTERED::child"))
def test_renameForDragAndDrop():
d = getEmptyCol()
col = getEmptyCol()
def deckNames():
return [n.name for n in d.decks.all_names_and_ids(skip_empty_default=True)]
return [n.name for n in col.decks.all_names_and_ids(skip_empty_default=True)]
languages_did = d.decks.id("Languages")
chinese_did = d.decks.id("Chinese")
hsk_did = d.decks.id("Chinese::HSK")
languages_did = col.decks.id("Languages")
chinese_did = col.decks.id("Chinese")
hsk_did = col.decks.id("Chinese::HSK")
# Renaming also renames children
d.decks.renameForDragAndDrop(chinese_did, languages_did)
col.decks.renameForDragAndDrop(chinese_did, languages_did)
assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"]
# Dragging a deck onto itself is a no-op
d.decks.renameForDragAndDrop(languages_did, languages_did)
# Dragging a col onto itself is a no-op
col.decks.renameForDragAndDrop(languages_did, languages_did)
assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"]
# Dragging a deck onto its parent is a no-op
d.decks.renameForDragAndDrop(hsk_did, chinese_did)
# Dragging a col onto its parent is a no-op
col.decks.renameForDragAndDrop(hsk_did, chinese_did)
assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"]
# Dragging a deck onto a descendant is a no-op
d.decks.renameForDragAndDrop(languages_did, hsk_did)
# Dragging a col onto a descendant is a no-op
col.decks.renameForDragAndDrop(languages_did, hsk_did)
assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"]
# Can drag a grandchild onto its grandparent. It becomes a child
d.decks.renameForDragAndDrop(hsk_did, languages_did)
col.decks.renameForDragAndDrop(hsk_did, languages_did)
assert deckNames() == ["Languages", "Languages::Chinese", "Languages::HSK"]
# Can drag a deck onto its sibling
d.decks.renameForDragAndDrop(hsk_did, chinese_did)
# Can drag a col onto its sibling
col.decks.renameForDragAndDrop(hsk_did, chinese_did)
assert deckNames() == ["Languages", "Languages::Chinese", "Languages::Chinese::HSK"]
# Can drag a deck back to the top level
d.decks.renameForDragAndDrop(chinese_did, None)
# Can drag a col back to the top level
col.decks.renameForDragAndDrop(chinese_did, None)
assert deckNames() == ["Chinese", "Chinese::HSK", "Languages"]
# Dragging a top level deck to the top level is a no-op
d.decks.renameForDragAndDrop(chinese_did, None)
# Dragging a top level col to the top level is a no-op
col.decks.renameForDragAndDrop(chinese_did, None)
assert deckNames() == ["Chinese", "Chinese::HSK", "Languages"]
# decks are renamed if necessary
new_hsk_did = d.decks.id("hsk")
d.decks.renameForDragAndDrop(new_hsk_did, chinese_did)
new_hsk_did = col.decks.id("hsk")
col.decks.renameForDragAndDrop(new_hsk_did, chinese_did)
assert deckNames() == ["Chinese", "Chinese::HSK", "Chinese::hsk+", "Languages"]
d.decks.rem(new_hsk_did)
col.decks.rem(new_hsk_did)
# '' is a convenient alias for the top level DID
d.decks.renameForDragAndDrop(hsk_did, "")
col.decks.renameForDragAndDrop(hsk_did, "")
assert deckNames() == ["Chinese", "HSK", "Languages"]

View file

@ -16,25 +16,25 @@ def getEmptyCol():
return col
deck = None
col = None
ds = None
testDir = os.path.dirname(__file__)
def setup1():
global deck
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "foo"
f["Back"] = "bar<br>"
f.tags = ["tag", "tag2"]
deck.addNote(f)
# with a different deck
f = deck.newNote()
f["Front"] = "baz"
f["Back"] = "qux"
f.model()["did"] = deck.decks.id("new deck")
deck.addNote(f)
global col
col = getEmptyCol()
note = col.newNote()
note["Front"] = "foo"
note["Back"] = "bar<br>"
note.tags = ["tag", "tag2"]
col.addNote(note)
# with a different col
note = col.newNote()
note["Front"] = "baz"
note["Back"] = "qux"
note.model()["did"] = col.decks.id("new col")
col.addNote(note)
##########################################################################
@ -42,23 +42,23 @@ def setup1():
def test_export_anki():
setup1()
# create a new deck with its own conf to test conf copying
did = deck.decks.id("test")
dobj = deck.decks.get(did)
confId = deck.decks.add_config_returning_id("newconf")
conf = deck.decks.get_config(confId)
# create a new col with its own conf to test conf copying
did = col.decks.id("test")
dobj = col.decks.get(did)
confId = col.decks.add_config_returning_id("newconf")
conf = col.decks.get_config(confId)
conf["new"]["perDay"] = 5
deck.decks.save(conf)
deck.decks.setConf(dobj, confId)
col.decks.save(conf)
col.decks.setConf(dobj, confId)
# export
e = AnkiExporter(deck)
e = AnkiExporter(col)
fd, newname = tempfile.mkstemp(prefix="ankitest", suffix=".anki2")
newname = str(newname)
os.close(fd)
os.unlink(newname)
e.exportInto(newname)
# exporting should not have changed conf for original deck
conf = deck.decks.confForDid(did)
conf = col.decks.confForDid(did)
assert conf["id"] != 1
# connect to new deck
d2 = aopen(newname)
@ -85,12 +85,12 @@ def test_export_anki():
def test_export_ankipkg():
setup1()
# add a test file to the media folder
with open(os.path.join(deck.media.dir(), "今日.mp3"), "w") as f:
f.write("test")
n = deck.newNote()
with open(os.path.join(col.media.dir(), "今日.mp3"), "w") as note:
note.write("test")
n = col.newNote()
n["Front"] = "[sound:今日.mp3]"
deck.addNote(n)
e = AnkiPackageExporter(deck)
col.addNote(n)
e = AnkiPackageExporter(col)
fd, newname = tempfile.mkstemp(prefix="ankitest", suffix=".apkg")
newname = str(newname)
os.close(fd)
@ -101,23 +101,23 @@ def test_export_ankipkg():
@errorsAfterMidnight
def test_export_anki_due():
setup1()
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "foo"
deck.addNote(f)
deck.crt -= 86400 * 10
deck.flush()
deck.sched.reset()
c = deck.sched.getCard()
deck.sched.answerCard(c, 3)
deck.sched.answerCard(c, 3)
col = getEmptyCol()
note = col.newNote()
note["Front"] = "foo"
col.addNote(note)
col.crt -= 86400 * 10
col.flush()
col.sched.reset()
c = col.sched.getCard()
col.sched.answerCard(c, 3)
col.sched.answerCard(c, 3)
# should have ivl of 1, due on day 11
assert c.ivl == 1
assert c.due == 11
assert deck.sched.today == 10
assert c.due - deck.sched.today == 1
assert col.sched.today == 10
assert c.due - col.sched.today == 1
# export
e = AnkiExporter(deck)
e = AnkiExporter(col)
e.includeSched = True
fd, newname = tempfile.mkstemp(prefix="ankitest", suffix=".anki2")
newname = str(newname)
@ -135,28 +135,28 @@ def test_export_anki_due():
# def test_export_textcard():
# setup1()
# e = TextCardExporter(deck)
# f = unicode(tempfile.mkstemp(prefix="ankitest")[1])
# os.unlink(f)
# e.exportInto(f)
# e = TextCardExporter(col)
# note = unicode(tempfile.mkstemp(prefix="ankitest")[1])
# os.unlink(note)
# e.exportInto(note)
# e.includeTags = True
# e.exportInto(f)
# e.exportInto(note)
def test_export_textnote():
setup1()
e = TextNoteExporter(deck)
fd, f = tempfile.mkstemp(prefix="ankitest")
f = str(f)
e = TextNoteExporter(col)
fd, note = tempfile.mkstemp(prefix="ankitest")
note = str(note)
os.close(fd)
os.unlink(f)
e.exportInto(f)
with open(f) as file:
os.unlink(note)
e.exportInto(note)
with open(note) as file:
assert file.readline() == "foo\tbar<br>\ttag tag2\n"
e.includeTags = False
e.includeHTML = False
e.exportInto(f)
with open(f) as file:
e.exportInto(note)
with open(note) as file:
assert file.readline() == "foo\tbar\n"

View file

@ -12,284 +12,284 @@ class DummyCollection:
def test_findCards():
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "dog"
f["Back"] = "cat"
f.tags.append("monkey animal_1 * %")
deck.addNote(f)
f1id = f.id
firstCardId = f.cards()[0].id
f = deck.newNote()
f["Front"] = "goats are fun"
f["Back"] = "sheep"
f.tags.append("sheep goat horse animal11")
deck.addNote(f)
f2id = f.id
f = deck.newNote()
f["Front"] = "cat"
f["Back"] = "sheep"
deck.addNote(f)
catCard = f.cards()[0]
m = deck.models.current()
m = deck.models.copy(m)
mm = deck.models
col = getEmptyCol()
note = col.newNote()
note["Front"] = "dog"
note["Back"] = "cat"
note.tags.append("monkey animal_1 * %")
col.addNote(note)
f1id = note.id
firstCardId = note.cards()[0].id
note = col.newNote()
note["Front"] = "goats are fun"
note["Back"] = "sheep"
note.tags.append("sheep goat horse animal11")
col.addNote(note)
f2id = note.id
note = col.newNote()
note["Front"] = "cat"
note["Back"] = "sheep"
col.addNote(note)
catCard = note.cards()[0]
m = col.models.current()
m = col.models.copy(m)
mm = col.models
t = mm.newTemplate("Reverse")
t["qfmt"] = "{{Back}}"
t["afmt"] = "{{Front}}"
mm.addTemplate(m, t)
mm.save(m)
f = deck.newNote()
f["Front"] = "test"
f["Back"] = "foo bar"
deck.addNote(f)
deck.save()
latestCardIds = [c.id for c in f.cards()]
note = col.newNote()
note["Front"] = "test"
note["Back"] = "foo bar"
col.addNote(note)
col.save()
latestCardIds = [c.id for c in note.cards()]
# tag searches
assert len(deck.findCards("tag:*")) == 5
assert len(deck.findCards("tag:\\*")) == 1
assert len(deck.findCards("tag:%")) == 5
assert len(deck.findCards("tag:\\%")) == 1
assert len(deck.findCards("tag:animal_1")) == 2
assert len(deck.findCards("tag:animal\\_1")) == 1
assert not deck.findCards("tag:donkey")
assert len(deck.findCards("tag:sheep")) == 1
assert len(deck.findCards("tag:sheep tag:goat")) == 1
assert len(deck.findCards("tag:sheep tag:monkey")) == 0
assert len(deck.findCards("tag:monkey")) == 1
assert len(deck.findCards("tag:sheep -tag:monkey")) == 1
assert len(deck.findCards("-tag:sheep")) == 4
deck.tags.bulkAdd(deck.db.list("select id from notes"), "foo bar")
assert len(deck.findCards("tag:foo")) == len(deck.findCards("tag:bar")) == 5
deck.tags.bulkRem(deck.db.list("select id from notes"), "foo")
assert len(deck.findCards("tag:foo")) == 0
assert len(deck.findCards("tag:bar")) == 5
assert len(col.findCards("tag:*")) == 5
assert len(col.findCards("tag:\\*")) == 1
assert len(col.findCards("tag:%")) == 5
assert len(col.findCards("tag:\\%")) == 1
assert len(col.findCards("tag:animal_1")) == 2
assert len(col.findCards("tag:animal\\_1")) == 1
assert not col.findCards("tag:donkey")
assert len(col.findCards("tag:sheep")) == 1
assert len(col.findCards("tag:sheep tag:goat")) == 1
assert len(col.findCards("tag:sheep tag:monkey")) == 0
assert len(col.findCards("tag:monkey")) == 1
assert len(col.findCards("tag:sheep -tag:monkey")) == 1
assert len(col.findCards("-tag:sheep")) == 4
col.tags.bulkAdd(col.db.list("select id from notes"), "foo bar")
assert len(col.findCards("tag:foo")) == len(col.findCards("tag:bar")) == 5
col.tags.bulkRem(col.db.list("select id from notes"), "foo")
assert len(col.findCards("tag:foo")) == 0
assert len(col.findCards("tag:bar")) == 5
# text searches
assert len(deck.findCards("cat")) == 2
assert len(deck.findCards("cat -dog")) == 1
assert len(deck.findCards("cat -dog")) == 1
assert len(deck.findCards("are goats")) == 1
assert len(deck.findCards('"are goats"')) == 0
assert len(deck.findCards('"goats are"')) == 1
assert len(col.findCards("cat")) == 2
assert len(col.findCards("cat -dog")) == 1
assert len(col.findCards("cat -dog")) == 1
assert len(col.findCards("are goats")) == 1
assert len(col.findCards('"are goats"')) == 0
assert len(col.findCards('"goats are"')) == 1
# card states
c = f.cards()[0]
c = note.cards()[0]
c.queue = c.type = CARD_TYPE_REV
assert deck.findCards("is:review") == []
assert col.findCards("is:review") == []
c.flush()
assert deck.findCards("is:review") == [c.id]
assert deck.findCards("is:due") == []
assert col.findCards("is:review") == [c.id]
assert col.findCards("is:due") == []
c.due = 0
c.queue = QUEUE_TYPE_REV
c.flush()
assert deck.findCards("is:due") == [c.id]
assert len(deck.findCards("-is:due")) == 4
assert col.findCards("is:due") == [c.id]
assert len(col.findCards("-is:due")) == 4
c.queue = -1
# ensure this card gets a later mod time
c.flush()
deck.db.execute("update cards set mod = mod + 1 where id = ?", c.id)
assert deck.findCards("is:suspended") == [c.id]
col.db.execute("update cards set mod = mod + 1 where id = ?", c.id)
assert col.findCards("is:suspended") == [c.id]
# nids
assert deck.findCards("nid:54321") == []
assert len(deck.findCards("nid:%d" % f.id)) == 2
assert len(deck.findCards("nid:%d,%d" % (f1id, f2id))) == 2
assert col.findCards("nid:54321") == []
assert len(col.findCards(f"nid:{note.id}")) == 2
assert len(col.findCards(f"nid:{f1id},{f2id}")) == 2
# templates
assert len(deck.findCards("card:foo")) == 0
assert len(deck.findCards('"card:card 1"')) == 4
assert len(deck.findCards("card:reverse")) == 1
assert len(deck.findCards("card:1")) == 4
assert len(deck.findCards("card:2")) == 1
assert len(col.findCards("card:foo")) == 0
assert len(col.findCards('"card:card 1"')) == 4
assert len(col.findCards("card:reverse")) == 1
assert len(col.findCards("card:1")) == 4
assert len(col.findCards("card:2")) == 1
# fields
assert len(deck.findCards("front:dog")) == 1
assert len(deck.findCards("-front:dog")) == 4
assert len(deck.findCards("front:sheep")) == 0
assert len(deck.findCards("back:sheep")) == 2
assert len(deck.findCards("-back:sheep")) == 3
assert len(deck.findCards("front:do")) == 0
assert len(deck.findCards("front:*")) == 5
assert len(col.findCards("front:dog")) == 1
assert len(col.findCards("-front:dog")) == 4
assert len(col.findCards("front:sheep")) == 0
assert len(col.findCards("back:sheep")) == 2
assert len(col.findCards("-back:sheep")) == 3
assert len(col.findCards("front:do")) == 0
assert len(col.findCards("front:*")) == 5
# ordering
deck.conf["sortType"] = "noteCrt"
deck.flush()
assert deck.findCards("front:*", order=True)[-1] in latestCardIds
assert deck.findCards("", order=True)[-1] in latestCardIds
deck.conf["sortType"] = "noteFld"
deck.flush()
assert deck.findCards("", order=True)[0] == catCard.id
assert deck.findCards("", order=True)[-1] in latestCardIds
deck.conf["sortType"] = "cardMod"
deck.flush()
assert deck.findCards("", order=True)[-1] in latestCardIds
assert deck.findCards("", order=True)[0] == firstCardId
deck.conf["sortBackwards"] = True
deck.flush()
assert deck.findCards("", order=True)[0] in latestCardIds
col.conf["sortType"] = "noteCrt"
col.flush()
assert col.findCards("front:*", order=True)[-1] in latestCardIds
assert col.findCards("", order=True)[-1] in latestCardIds
col.conf["sortType"] = "noteFld"
col.flush()
assert col.findCards("", order=True)[0] == catCard.id
assert col.findCards("", order=True)[-1] in latestCardIds
col.conf["sortType"] = "cardMod"
col.flush()
assert col.findCards("", order=True)[-1] in latestCardIds
assert col.findCards("", order=True)[0] == firstCardId
col.conf["sortBackwards"] = True
col.flush()
assert col.findCards("", order=True)[0] in latestCardIds
assert (
deck.find_cards("", order=BuiltinSortKind.CARD_DUE, reverse=False)[0]
col.find_cards("", order=BuiltinSortKind.CARD_DUE, reverse=False)[0]
== firstCardId
)
assert (
deck.find_cards("", order=BuiltinSortKind.CARD_DUE, reverse=True)[0]
col.find_cards("", order=BuiltinSortKind.CARD_DUE, reverse=True)[0]
!= firstCardId
)
# model
assert len(deck.findCards("note:basic")) == 3
assert len(deck.findCards("-note:basic")) == 2
assert len(deck.findCards("-note:foo")) == 5
# deck
assert len(deck.findCards("deck:default")) == 5
assert len(deck.findCards("-deck:default")) == 0
assert len(deck.findCards("-deck:foo")) == 5
assert len(deck.findCards("deck:def*")) == 5
assert len(deck.findCards("deck:*EFAULT")) == 5
assert len(deck.findCards("deck:*cefault")) == 0
assert len(col.findCards("note:basic")) == 3
assert len(col.findCards("-note:basic")) == 2
assert len(col.findCards("-note:foo")) == 5
# col
assert len(col.findCards("deck:default")) == 5
assert len(col.findCards("-deck:default")) == 0
assert len(col.findCards("-deck:foo")) == 5
assert len(col.findCards("deck:def*")) == 5
assert len(col.findCards("deck:*EFAULT")) == 5
assert len(col.findCards("deck:*cefault")) == 0
# full search
f = deck.newNote()
f["Front"] = "hello<b>world</b>"
f["Back"] = "abc"
deck.addNote(f)
note = col.newNote()
note["Front"] = "hello<b>world</b>"
note["Back"] = "abc"
col.addNote(note)
# as it's the sort field, it matches
assert len(deck.findCards("helloworld")) == 2
# assert len(deck.findCards("helloworld", full=True)) == 2
assert len(col.findCards("helloworld")) == 2
# assert len(col.findCards("helloworld", full=True)) == 2
# if we put it on the back, it won't
(f["Front"], f["Back"]) = (f["Back"], f["Front"])
f.flush()
assert len(deck.findCards("helloworld")) == 0
# assert len(deck.findCards("helloworld", full=True)) == 2
# assert len(deck.findCards("back:helloworld", full=True)) == 2
(note["Front"], note["Back"]) = (note["Back"], note["Front"])
note.flush()
assert len(col.findCards("helloworld")) == 0
# assert len(col.findCards("helloworld", full=True)) == 2
# assert len(col.findCards("back:helloworld", full=True)) == 2
# searching for an invalid special tag should not error
with pytest.raises(Exception):
len(deck.findCards("is:invalid"))
# should be able to limit to parent deck, no children
id = deck.db.scalar("select id from cards limit 1")
deck.db.execute(
"update cards set did = ? where id = ?", deck.decks.id("Default::Child"), id
len(col.findCards("is:invalid"))
# should be able to limit to parent col, no children
id = col.db.scalar("select id from cards limit 1")
col.db.execute(
"update cards set did = ? where id = ?", col.decks.id("Default::Child"), id
)
deck.save()
assert len(deck.findCards("deck:default")) == 7
assert len(deck.findCards("deck:default::child")) == 1
assert len(deck.findCards("deck:default -deck:default::*")) == 6
col.save()
assert len(col.findCards("deck:default")) == 7
assert len(col.findCards("deck:default::child")) == 1
assert len(col.findCards("deck:default -deck:default::*")) == 6
# properties
id = deck.db.scalar("select id from cards limit 1")
deck.db.execute(
id = col.db.scalar("select id from cards limit 1")
col.db.execute(
"update cards set queue=2, ivl=10, reps=20, due=30, factor=2200 "
"where id = ?",
id,
)
assert len(deck.findCards("prop:ivl>5")) == 1
assert len(deck.findCards("prop:ivl<5")) > 1
assert len(deck.findCards("prop:ivl>=5")) == 1
assert len(deck.findCards("prop:ivl=9")) == 0
assert len(deck.findCards("prop:ivl=10")) == 1
assert len(deck.findCards("prop:ivl!=10")) > 1
assert len(deck.findCards("prop:due>0")) == 1
assert len(col.findCards("prop:ivl>5")) == 1
assert len(col.findCards("prop:ivl<5")) > 1
assert len(col.findCards("prop:ivl>=5")) == 1
assert len(col.findCards("prop:ivl=9")) == 0
assert len(col.findCards("prop:ivl=10")) == 1
assert len(col.findCards("prop:ivl!=10")) > 1
assert len(col.findCards("prop:due>0")) == 1
# due dates should work
assert len(deck.findCards("prop:due=29")) == 0
assert len(deck.findCards("prop:due=30")) == 1
assert len(col.findCards("prop:due=29")) == 0
assert len(col.findCards("prop:due=30")) == 1
# ease factors
assert len(deck.findCards("prop:ease=2.3")) == 0
assert len(deck.findCards("prop:ease=2.2")) == 1
assert len(deck.findCards("prop:ease>2")) == 1
assert len(deck.findCards("-prop:ease>2")) > 1
assert len(col.findCards("prop:ease=2.3")) == 0
assert len(col.findCards("prop:ease=2.2")) == 1
assert len(col.findCards("prop:ease>2")) == 1
assert len(col.findCards("-prop:ease>2")) > 1
# recently failed
if not isNearCutoff():
assert len(deck.findCards("rated:1:1")) == 0
assert len(deck.findCards("rated:1:2")) == 0
c = deck.sched.getCard()
deck.sched.answerCard(c, 2)
assert len(deck.findCards("rated:1:1")) == 0
assert len(deck.findCards("rated:1:2")) == 1
c = deck.sched.getCard()
deck.sched.answerCard(c, 1)
assert len(deck.findCards("rated:1:1")) == 1
assert len(deck.findCards("rated:1:2")) == 1
assert len(deck.findCards("rated:1")) == 2
assert len(deck.findCards("rated:0:2")) == 0
assert len(deck.findCards("rated:2:2")) == 1
assert len(col.findCards("rated:1:1")) == 0
assert len(col.findCards("rated:1:2")) == 0
c = col.sched.getCard()
col.sched.answerCard(c, 2)
assert len(col.findCards("rated:1:1")) == 0
assert len(col.findCards("rated:1:2")) == 1
c = col.sched.getCard()
col.sched.answerCard(c, 1)
assert len(col.findCards("rated:1:1")) == 1
assert len(col.findCards("rated:1:2")) == 1
assert len(col.findCards("rated:1")) == 2
assert len(col.findCards("rated:0:2")) == 0
assert len(col.findCards("rated:2:2")) == 1
# added
assert len(deck.findCards("added:0")) == 0
deck.db.execute("update cards set id = id - 86400*1000 where id = ?", id)
assert len(deck.findCards("added:1")) == deck.cardCount() - 1
assert len(deck.findCards("added:2")) == deck.cardCount()
assert len(col.findCards("added:0")) == 0
col.db.execute("update cards set id = id - 86400*1000 where id = ?", id)
assert len(col.findCards("added:1")) == col.cardCount() - 1
assert len(col.findCards("added:2")) == col.cardCount()
else:
print("some find tests disabled near cutoff")
# empty field
assert len(deck.findCards("front:")) == 0
f = deck.newNote()
f["Front"] = ""
f["Back"] = "abc2"
assert deck.addNote(f) == 1
assert len(deck.findCards("front:")) == 1
assert len(col.findCards("front:")) == 0
note = col.newNote()
note["Front"] = ""
note["Back"] = "abc2"
assert col.addNote(note) == 1
assert len(col.findCards("front:")) == 1
# OR searches and nesting
assert len(deck.findCards("tag:monkey or tag:sheep")) == 2
assert len(deck.findCards("(tag:monkey OR tag:sheep)")) == 2
assert len(deck.findCards("-(tag:monkey OR tag:sheep)")) == 6
assert len(deck.findCards("tag:monkey or (tag:sheep sheep)")) == 2
assert len(deck.findCards("tag:monkey or (tag:sheep octopus)")) == 1
assert len(col.findCards("tag:monkey or tag:sheep")) == 2
assert len(col.findCards("(tag:monkey OR tag:sheep)")) == 2
assert len(col.findCards("-(tag:monkey OR tag:sheep)")) == 6
assert len(col.findCards("tag:monkey or (tag:sheep sheep)")) == 2
assert len(col.findCards("tag:monkey or (tag:sheep octopus)")) == 1
# flag
with pytest.raises(Exception):
deck.findCards("flag:12")
col.findCards("flag:12")
def test_findReplace():
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "foo"
f["Back"] = "bar"
deck.addNote(f)
f2 = deck.newNote()
f2["Front"] = "baz"
f2["Back"] = "foo"
deck.addNote(f2)
nids = [f.id, f2.id]
col = getEmptyCol()
note = col.newNote()
note["Front"] = "foo"
note["Back"] = "bar"
col.addNote(note)
note2 = col.newNote()
note2["Front"] = "baz"
note2["Back"] = "foo"
col.addNote(note2)
nids = [note.id, note2.id]
# should do nothing
assert deck.findReplace(nids, "abc", "123") == 0
assert col.findReplace(nids, "abc", "123") == 0
# global replace
assert deck.findReplace(nids, "foo", "qux") == 2
f.load()
assert f["Front"] == "qux"
f2.load()
assert f2["Back"] == "qux"
assert col.findReplace(nids, "foo", "qux") == 2
note.load()
assert note["Front"] == "qux"
note2.load()
assert note2["Back"] == "qux"
# single field replace
assert deck.findReplace(nids, "qux", "foo", field="Front") == 1
f.load()
assert f["Front"] == "foo"
f2.load()
assert f2["Back"] == "qux"
assert col.findReplace(nids, "qux", "foo", field="Front") == 1
note.load()
assert note["Front"] == "foo"
note2.load()
assert note2["Back"] == "qux"
# regex replace
assert deck.findReplace(nids, "B.r", "reg") == 0
f.load()
assert f["Back"] != "reg"
assert deck.findReplace(nids, "B.r", "reg", regex=True) == 1
f.load()
assert f["Back"] == "reg"
assert col.findReplace(nids, "B.r", "reg") == 0
note.load()
assert note["Back"] != "reg"
assert col.findReplace(nids, "B.r", "reg", regex=True) == 1
note.load()
assert note["Back"] == "reg"
def test_findDupes():
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "foo"
f["Back"] = "bar"
deck.addNote(f)
f2 = deck.newNote()
f2["Front"] = "baz"
f2["Back"] = "bar"
deck.addNote(f2)
f3 = deck.newNote()
col = getEmptyCol()
note = col.newNote()
note["Front"] = "foo"
note["Back"] = "bar"
col.addNote(note)
note2 = col.newNote()
note2["Front"] = "baz"
note2["Back"] = "bar"
col.addNote(note2)
f3 = col.newNote()
f3["Front"] = "quux"
f3["Back"] = "bar"
deck.addNote(f3)
f4 = deck.newNote()
col.addNote(f3)
f4 = col.newNote()
f4["Front"] = "quuux"
f4["Back"] = "nope"
deck.addNote(f4)
r = deck.findDupes("Back")
col.addNote(f4)
r = col.findDupes("Back")
assert r[0][0] == "bar"
assert len(r[0][1]) == 3
# valid search
r = deck.findDupes("Back", "bar")
r = col.findDupes("Back", "bar")
assert r[0][0] == "bar"
assert len(r[0][1]) == 3
# excludes everything
r = deck.findDupes("Back", "invalid")
r = col.findDupes("Back", "invalid")
assert not r
# front isn't dupe
assert deck.findDupes("Front") == []
assert col.findDupes("Front") == []

View file

@ -37,8 +37,8 @@ def test_anki2_mediadupes():
mid = n.model()["id"]
tmp.addNote(n)
# add that sound to media folder
with open(os.path.join(tmp.media.dir(), "foo.mp3"), "w") as f:
f.write("foo")
with open(os.path.join(tmp.media.dir(), "foo.mp3"), "w") as note:
note.write("foo")
tmp.close()
# it should be imported correctly into an empty deck
empty = getEmptyCol()
@ -55,8 +55,8 @@ def test_anki2_mediadupes():
# if the local file content is different, and import should trigger a
# rename
empty.remove_cards_and_orphaned_notes(empty.db.list("select id from cards"))
with open(os.path.join(empty.media.dir(), "foo.mp3"), "w") as f:
f.write("bar")
with open(os.path.join(empty.media.dir(), "foo.mp3"), "w") as note:
note.write("bar")
imp = Anki2Importer(empty, tmp.path)
imp.run()
assert sorted(os.listdir(empty.media.dir())) == ["foo.mp3", "foo_%s.mp3" % mid]
@ -65,8 +65,8 @@ def test_anki2_mediadupes():
# if the localized media file already exists, we rewrite the note and
# media
empty.remove_cards_and_orphaned_notes(empty.db.list("select id from cards"))
with open(os.path.join(empty.media.dir(), "foo.mp3"), "w") as f:
f.write("bar")
with open(os.path.join(empty.media.dir(), "foo.mp3"), "w") as note:
note.write("bar")
imp = Anki2Importer(empty, tmp.path)
imp.run()
assert sorted(os.listdir(empty.media.dir())) == ["foo.mp3", "foo_%s.mp3" % mid]
@ -89,8 +89,8 @@ def test_apkg():
assert os.listdir(tmp.media.dir()) == ["foo.wav"]
# but if the local file has different data, it will rename
tmp.remove_cards_and_orphaned_notes(tmp.db.list("select id from cards"))
with open(os.path.join(tmp.media.dir(), "foo.wav"), "w") as f:
f.write("xyz")
with open(os.path.join(tmp.media.dir(), "foo.wav"), "w") as note:
note.write("xyz")
imp = AnkiPackageImporter(tmp, apkg)
imp.run()
assert len(os.listdir(tmp.media.dir())) == 2
@ -147,9 +147,9 @@ def test_anki2_updates():
def test_csv():
deck = getEmptyCol()
col = getEmptyCol()
file = str(os.path.join(testDir, "support/text-2fields.txt"))
i = TextImporter(deck, file)
i = TextImporter(col, file)
i.initMapping()
i.run()
# four problems - too many & too few fields, a missing front, and a
@ -161,7 +161,7 @@ def test_csv():
assert len(i.log) == 10
assert i.total == 5
# but importing should not clobber tags if they're unmapped
n = deck.getNote(deck.db.scalar("select id from notes"))
n = col.getNote(col.db.scalar("select id from notes"))
n.addTag("test")
n.flush()
i.run()
@ -172,58 +172,58 @@ def test_csv():
i.run()
assert i.total == 0
# and if dupes mode, will reimport everything
assert deck.cardCount() == 5
assert col.cardCount() == 5
i.importMode = 2
i.run()
# includes repeated field
assert i.total == 6
assert deck.cardCount() == 11
deck.close()
assert col.cardCount() == 11
col.close()
def test_csv2():
deck = getEmptyCol()
mm = deck.models
col = getEmptyCol()
mm = col.models
m = mm.current()
f = mm.newField("Three")
mm.addField(m, f)
note = mm.newField("Three")
mm.addField(m, note)
mm.save(m)
n = deck.newNote()
n = col.newNote()
n["Front"] = "1"
n["Back"] = "2"
n["Three"] = "3"
deck.addNote(n)
col.addNote(n)
# an update with unmapped fields should not clobber those fields
file = str(os.path.join(testDir, "support/text-update.txt"))
i = TextImporter(deck, file)
i = TextImporter(col, file)
i.initMapping()
i.run()
n.load()
assert n["Front"] == "1"
assert n["Back"] == "x"
assert n["Three"] == "3"
deck.close()
col.close()
def test_tsv_tag_modified():
deck = getEmptyCol()
mm = deck.models
col = getEmptyCol()
mm = col.models
m = mm.current()
f = mm.newField("Top")
mm.addField(m, f)
note = mm.newField("Top")
mm.addField(m, note)
mm.save(m)
n = deck.newNote()
n = col.newNote()
n["Front"] = "1"
n["Back"] = "2"
n["Top"] = "3"
n.addTag("four")
deck.addNote(n)
col.addNote(n)
# https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file
with NamedTemporaryFile(mode="w", delete=False) as tf:
tf.write("1\tb\tc\n")
tf.flush()
i = TextImporter(deck, tf.name)
i = TextImporter(col, tf.name)
i.initMapping()
i.tagModified = "boom"
i.run()
@ -238,29 +238,29 @@ def test_tsv_tag_modified():
assert len(n.tags) == 2
assert i.updateCount == 1
deck.close()
col.close()
def test_tsv_tag_multiple_tags():
deck = getEmptyCol()
mm = deck.models
col = getEmptyCol()
mm = col.models
m = mm.current()
f = mm.newField("Top")
mm.addField(m, f)
note = mm.newField("Top")
mm.addField(m, note)
mm.save(m)
n = deck.newNote()
n = col.newNote()
n["Front"] = "1"
n["Back"] = "2"
n["Top"] = "3"
n.addTag("four")
n.addTag("five")
deck.addNote(n)
col.addNote(n)
# https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file
with NamedTemporaryFile(mode="w", delete=False) as tf:
tf.write("1\tb\tc\n")
tf.flush()
i = TextImporter(deck, tf.name)
i = TextImporter(col, tf.name)
i.initMapping()
i.tagModified = "five six"
i.run()
@ -272,27 +272,27 @@ def test_tsv_tag_multiple_tags():
assert n["Top"] == "c"
assert list(sorted(n.tags)) == list(sorted(["four", "five", "six"]))
deck.close()
col.close()
def test_csv_tag_only_if_modified():
deck = getEmptyCol()
mm = deck.models
col = getEmptyCol()
mm = col.models
m = mm.current()
f = mm.newField("Left")
mm.addField(m, f)
note = mm.newField("Left")
mm.addField(m, note)
mm.save(m)
n = deck.newNote()
n = col.newNote()
n["Front"] = "1"
n["Back"] = "2"
n["Left"] = "3"
deck.addNote(n)
col.addNote(n)
# https://stackoverflow.com/questions/23212435/permission-denied-to-write-to-my-temporary-file
with NamedTemporaryFile(mode="w", delete=False) as tf:
tf.write("1,2,3\n")
tf.flush()
i = TextImporter(deck, tf.name)
i = TextImporter(col, tf.name)
i.initMapping()
i.tagModified = "right"
i.run()
@ -302,31 +302,31 @@ def test_csv_tag_only_if_modified():
assert n.tags == []
assert i.updateCount == 0
deck.close()
col.close()
@pytest.mark.filterwarnings("ignore:Using or importing the ABCs")
def test_supermemo_xml_01_unicode():
deck = getEmptyCol()
col = getEmptyCol()
file = str(os.path.join(testDir, "support/supermemo1.xml"))
i = SupermemoXmlImporter(deck, file)
i = SupermemoXmlImporter(col, file)
# i.META.logToStdOutput = True
i.run()
assert i.total == 1
cid = deck.db.scalar("select id from cards")
c = deck.getCard(cid)
cid = col.db.scalar("select id from cards")
c = col.getCard(cid)
# Applies A Factor-to-E Factor conversion
assert c.factor == 2879
assert c.reps == 7
deck.close()
col.close()
def test_mnemo():
deck = getEmptyCol()
col = getEmptyCol()
file = str(os.path.join(testDir, "support/mnemo.db"))
i = MnemosyneImporter(deck, file)
i = MnemosyneImporter(col, file)
i.run()
assert deck.cardCount() == 7
assert "a_longer_tag" in deck.tags.all()
assert deck.db.scalar("select count() from cards where type = 0") == 1
deck.close()
assert col.cardCount() == 7
assert "a_longer_tag" in col.tags.all()
assert col.db.scalar("select count() from cards where type = 0") == 1
col.close()

View file

@ -7,19 +7,19 @@ from tests.shared import getEmptyCol
def test_latex():
d = getEmptyCol()
col = getEmptyCol()
# change latex cmd to simulate broken build
import anki.latex
anki.latex.pngCommands[0][0] = "nolatex"
# add a note with latex
f = d.newNote()
f["Front"] = "[latex]hello[/latex]"
d.addNote(f)
note = col.newNote()
note["Front"] = "[latex]hello[/latex]"
col.addNote(note)
# but since latex couldn't run, there's nothing there
assert len(os.listdir(d.media.dir())) == 0
assert len(os.listdir(col.media.dir())) == 0
# check the error message
msg = f.cards()[0].q()
msg = note.cards()[0].q()
assert "executing nolatex" in msg
assert "installed" in msg
# check if we have latex installed, and abort test if we don't
@ -29,29 +29,29 @@ def test_latex():
# fix path
anki.latex.pngCommands[0][0] = "latex"
# check media db should cause latex to be generated
d.media.render_all_latex()
assert len(os.listdir(d.media.dir())) == 1
assert ".png" in f.cards()[0].q()
col.media.render_all_latex()
assert len(os.listdir(col.media.dir())) == 1
assert ".png" in note.cards()[0].q()
# adding new notes should cause generation on question display
f = d.newNote()
f["Front"] = "[latex]world[/latex]"
d.addNote(f)
f.cards()[0].q()
assert len(os.listdir(d.media.dir())) == 2
note = col.newNote()
note["Front"] = "[latex]world[/latex]"
col.addNote(note)
note.cards()[0].q()
assert len(os.listdir(col.media.dir())) == 2
# another note with the same media should reuse
f = d.newNote()
f["Front"] = " [latex]world[/latex]"
d.addNote(f)
assert len(os.listdir(d.media.dir())) == 2
oldcard = f.cards()[0]
note = col.newNote()
note["Front"] = " [latex]world[/latex]"
col.addNote(note)
assert len(os.listdir(col.media.dir())) == 2
oldcard = note.cards()[0]
assert ".png" in oldcard.q()
# if we turn off building, then previous cards should work, but cards with
# missing media will show a broken image
anki.latex.build = False
f = d.newNote()
f["Front"] = "[latex]foo[/latex]"
d.addNote(f)
assert len(os.listdir(d.media.dir())) == 2
note = col.newNote()
note["Front"] = "[latex]foo[/latex]"
col.addNote(note)
assert len(os.listdir(col.media.dir())) == 2
assert ".png" in oldcard.q()
# turn it on again so other test don't suffer
anki.latex.build = True
@ -87,9 +87,9 @@ def test_latex():
def _test_includes_bad_command(bad):
d = getEmptyCol()
f = d.newNote()
f["Front"] = "[latex]%s[/latex]" % bad
d.addNote(f)
q = f.cards()[0].q()
col = getEmptyCol()
note = col.newNote()
note["Front"] = "[latex]%s[/latex]" % bad
col.addNote(note)
q = note.cards()[0].q()
return ("'%s' is not allowed on cards" % bad in q, "Card content: %s" % q)

View file

@ -8,25 +8,25 @@ from .shared import getEmptyCol, testDir
# copying files to media folder
def test_add():
d = getEmptyCol()
col = getEmptyCol()
dir = tempfile.mkdtemp(prefix="anki")
path = os.path.join(dir, "foo.jpg")
with open(path, "w") as f:
f.write("hello")
with open(path, "w") as note:
note.write("hello")
# new file, should preserve name
assert d.media.addFile(path) == "foo.jpg"
assert col.media.addFile(path) == "foo.jpg"
# adding the same file again should not create a duplicate
assert d.media.addFile(path) == "foo.jpg"
assert col.media.addFile(path) == "foo.jpg"
# but if it has a different sha1, it should
with open(path, "w") as f:
f.write("world")
assert d.media.addFile(path) == "foo-7c211433f02071597741e6ff5a8ea34789abbf43.jpg"
with open(path, "w") as note:
note.write("world")
assert col.media.addFile(path) == "foo-7c211433f02071597741e6ff5a8ea34789abbf43.jpg"
def test_strings():
d = getEmptyCol()
mf = d.media.filesInStr
mid = d.models.current()["id"]
col = getEmptyCol()
mf = col.media.filesInStr
mid = col.models.current()["id"]
assert mf(mid, "aoeu") == []
assert mf(mid, "aoeu<img src='foo.jpg'>ao") == ["foo.jpg"]
assert mf(mid, "aoeu<img src='foo.jpg' style='test'>ao") == ["foo.jpg"]
@ -42,37 +42,37 @@ def test_strings():
"fo",
]
assert mf(mid, "aou[sound:foo.mp3]aou") == ["foo.mp3"]
sp = d.media.strip
sp = col.media.strip
assert sp("aoeu") == "aoeu"
assert sp("aoeu[sound:foo.mp3]aoeu") == "aoeuaoeu"
assert sp("a<img src=yo>oeu") == "aoeu"
es = d.media.escapeImages
es = col.media.escapeImages
assert es("aoeu") == "aoeu"
assert es("<img src='http://foo.com'>") == "<img src='http://foo.com'>"
assert es('<img src="foo bar.jpg">') == '<img src="foo%20bar.jpg">'
def test_deckIntegration():
d = getEmptyCol()
col = getEmptyCol()
# create a media dir
d.media.dir()
col.media.dir()
# put a file into it
file = str(os.path.join(testDir, "support/fake.png"))
d.media.addFile(file)
col.media.addFile(file)
# add a note which references it
f = d.newNote()
f["Front"] = "one"
f["Back"] = "<img src='fake.png'>"
d.addNote(f)
note = col.newNote()
note["Front"] = "one"
note["Back"] = "<img src='fake.png'>"
col.addNote(note)
# and one which references a non-existent file
f = d.newNote()
f["Front"] = "one"
f["Back"] = "<img src='fake2.png'>"
d.addNote(f)
note = col.newNote()
note["Front"] = "one"
note["Back"] = "<img src='fake2.png'>"
col.addNote(note)
# and add another file which isn't used
with open(os.path.join(d.media.dir(), "foo.jpg"), "w") as f:
f.write("test")
with open(os.path.join(col.media.dir(), "foo.jpg"), "w") as note:
note.write("test")
# check media
ret = d.media.check()
ret = col.media.check()
assert ret.missing == ["fake2.png"]
assert ret.unused == ["foo.jpg"]

View file

@ -8,20 +8,20 @@ from tests.shared import getEmptyCol
def test_modelDelete():
deck = getEmptyCol()
f = deck.newNote()
f["Front"] = "1"
f["Back"] = "2"
deck.addNote(f)
assert deck.cardCount() == 1
deck.models.rem(deck.models.current())
assert deck.cardCount() == 0
col = getEmptyCol()
note = col.newNote()
note["Front"] = "1"
note["Back"] = "2"
col.addNote(note)
assert col.cardCount() == 1
col.models.rem(col.models.current())
assert col.cardCount() == 0
def test_modelCopy():
deck = getEmptyCol()
m = deck.models.current()
m2 = deck.models.copy(m)
col = getEmptyCol()
m = col.models.current()
m2 = col.models.copy(m)
assert m2["name"] == "Basic copy"
assert m2["id"] != m["id"]
assert len(m2["flds"]) == 2
@ -29,102 +29,104 @@ def test_modelCopy():
assert len(m2["flds"]) == len(m["flds"])
assert len(m["tmpls"]) == 1
assert len(m2["tmpls"]) == 1
assert deck.models.scmhash(m) == deck.models.scmhash(m2)
assert col.models.scmhash(m) == col.models.scmhash(m2)
def test_fields():
d = getEmptyCol()
f = d.newNote()
f["Front"] = "1"
f["Back"] = "2"
d.addNote(f)
m = d.models.current()
col = getEmptyCol()
note = col.newNote()
note["Front"] = "1"
note["Back"] = "2"
col.addNote(note)
m = col.models.current()
# make sure renaming a field updates the templates
d.models.renameField(m, m["flds"][0], "NewFront")
col.models.renameField(m, m["flds"][0], "NewFront")
assert "{{NewFront}}" in m["tmpls"][0]["qfmt"]
h = d.models.scmhash(m)
h = col.models.scmhash(m)
# add a field
f = d.models.newField("foo")
d.models.addField(m, f)
assert d.getNote(d.models.nids(m)[0]).fields == ["1", "2", ""]
assert d.models.scmhash(m) != h
note = col.models.newField("foo")
col.models.addField(m, note)
assert col.getNote(col.models.nids(m)[0]).fields == ["1", "2", ""]
assert col.models.scmhash(m) != h
# rename it
f = m["flds"][2]
d.models.renameField(m, f, "bar")
assert d.getNote(d.models.nids(m)[0])["bar"] == ""
note = m["flds"][2]
col.models.renameField(m, note, "bar")
assert col.getNote(col.models.nids(m)[0])["bar"] == ""
# delete back
d.models.remField(m, m["flds"][1])
assert d.getNote(d.models.nids(m)[0]).fields == ["1", ""]
col.models.remField(m, m["flds"][1])
assert col.getNote(col.models.nids(m)[0]).fields == ["1", ""]
# move 0 -> 1
d.models.moveField(m, m["flds"][0], 1)
assert d.getNote(d.models.nids(m)[0]).fields == ["", "1"]
col.models.moveField(m, m["flds"][0], 1)
assert col.getNote(col.models.nids(m)[0]).fields == ["", "1"]
# move 1 -> 0
d.models.moveField(m, m["flds"][1], 0)
assert d.getNote(d.models.nids(m)[0]).fields == ["1", ""]
col.models.moveField(m, m["flds"][1], 0)
assert col.getNote(col.models.nids(m)[0]).fields == ["1", ""]
# add another and put in middle
f = d.models.newField("baz")
d.models.addField(m, f)
f = d.getNote(d.models.nids(m)[0])
f["baz"] = "2"
f.flush()
assert d.getNote(d.models.nids(m)[0]).fields == ["1", "", "2"]
note = col.models.newField("baz")
col.models.addField(m, note)
note = col.getNote(col.models.nids(m)[0])
note["baz"] = "2"
note.flush()
assert col.getNote(col.models.nids(m)[0]).fields == ["1", "", "2"]
# move 2 -> 1
d.models.moveField(m, m["flds"][2], 1)
assert d.getNote(d.models.nids(m)[0]).fields == ["1", "2", ""]
col.models.moveField(m, m["flds"][2], 1)
assert col.getNote(col.models.nids(m)[0]).fields == ["1", "2", ""]
# move 0 -> 2
d.models.moveField(m, m["flds"][0], 2)
assert d.getNote(d.models.nids(m)[0]).fields == ["2", "", "1"]
col.models.moveField(m, m["flds"][0], 2)
assert col.getNote(col.models.nids(m)[0]).fields == ["2", "", "1"]
# move 0 -> 1
d.models.moveField(m, m["flds"][0], 1)
assert d.getNote(d.models.nids(m)[0]).fields == ["", "2", "1"]
col.models.moveField(m, m["flds"][0], 1)
assert col.getNote(col.models.nids(m)[0]).fields == ["", "2", "1"]
def test_templates():
d = getEmptyCol()
m = d.models.current()
mm = d.models
col = getEmptyCol()
m = col.models.current()
mm = col.models
t = mm.newTemplate("Reverse")
t["qfmt"] = "{{Back}}"
t["afmt"] = "{{Front}}"
mm.addTemplate(m, t)
mm.save(m)
f = d.newNote()
f["Front"] = "1"
f["Back"] = "2"
d.addNote(f)
assert d.cardCount() == 2
(c, c2) = f.cards()
note = col.newNote()
note["Front"] = "1"
note["Back"] = "2"
col.addNote(note)
assert col.cardCount() == 2
(c, c2) = note.cards()
# first card should have first ord
assert c.ord == 0
assert c2.ord == 1
# switch templates
d.models.moveTemplate(m, c.template(), 1)
col.models.moveTemplate(m, c.template(), 1)
c.load()
c2.load()
assert c.ord == 1
assert c2.ord == 0
# removing a template should delete its cards
d.models.remTemplate(m, m["tmpls"][0])
assert d.cardCount() == 1
col.models.remTemplate(m, m["tmpls"][0])
assert col.cardCount() == 1
# and should have updated the other cards' ordinals
c = f.cards()[0]
c = note.cards()[0]
assert c.ord == 0
assert stripHTML(c.q()) == "1"
# it shouldn't be possible to orphan notes by removing templates
t = mm.newTemplate("template name")
mm.addTemplate(m, t)
d.models.remTemplate(m, m["tmpls"][0])
col.models.remTemplate(m, m["tmpls"][0])
assert (
d.db.scalar("select count() from cards where nid not in (select id from notes)")
col.db.scalar(
"select count() from cards where nid not in (select id from notes)"
)
== 0
)
def test_cloze_ordinals():
d = getEmptyCol()
d.models.setCurrent(d.models.byName("Cloze"))
m = d.models.current()
mm = d.models
col = getEmptyCol()
col.models.setCurrent(col.models.byName("Cloze"))
m = col.models.current()
mm = col.models
# We replace the default Cloze template
t = mm.newTemplate("ChainedCloze")
@ -132,116 +134,120 @@ def test_cloze_ordinals():
t["afmt"] = "{{text:cloze:Text}}"
mm.addTemplate(m, t)
mm.save(m)
d.models.remTemplate(m, m["tmpls"][0])
col.models.remTemplate(m, m["tmpls"][0])
f = d.newNote()
f["Text"] = "{{c1::firstQ::firstA}}{{c2::secondQ::secondA}}"
d.addNote(f)
assert d.cardCount() == 2
(c, c2) = f.cards()
note = col.newNote()
note["Text"] = "{{c1::firstQ::firstA}}{{c2::secondQ::secondA}}"
col.addNote(note)
assert col.cardCount() == 2
(c, c2) = note.cards()
# first card should have first ord
assert c.ord == 0
assert c2.ord == 1
def test_text():
d = getEmptyCol()
m = d.models.current()
col = getEmptyCol()
m = col.models.current()
m["tmpls"][0]["qfmt"] = "{{text:Front}}"
d.models.save(m)
f = d.newNote()
f["Front"] = "hello<b>world"
d.addNote(f)
assert "helloworld" in f.cards()[0].q()
col.models.save(m)
note = col.newNote()
note["Front"] = "hello<b>world"
col.addNote(note)
assert "helloworld" in note.cards()[0].q()
def test_cloze():
d = getEmptyCol()
d.models.setCurrent(d.models.byName("Cloze"))
f = d.newNote()
assert f.model()["name"] == "Cloze"
col = getEmptyCol()
col.models.setCurrent(col.models.byName("Cloze"))
note = col.newNote()
assert note.model()["name"] == "Cloze"
# a cloze model with no clozes is not empty
f["Text"] = "nothing"
assert d.addNote(f)
note["Text"] = "nothing"
assert col.addNote(note)
# try with one cloze
f = d.newNote()
f["Text"] = "hello {{c1::world}}"
assert d.addNote(f) == 1
assert "hello <span class=cloze>[...]</span>" in f.cards()[0].q()
assert "hello <span class=cloze>world</span>" in f.cards()[0].a()
note = col.newNote()
note["Text"] = "hello {{c1::world}}"
assert col.addNote(note) == 1
assert "hello <span class=cloze>[...]</span>" in note.cards()[0].q()
assert "hello <span class=cloze>world</span>" in note.cards()[0].a()
# and with a comment
f = d.newNote()
f["Text"] = "hello {{c1::world::typical}}"
assert d.addNote(f) == 1
assert "<span class=cloze>[typical]</span>" in f.cards()[0].q()
assert "<span class=cloze>world</span>" in f.cards()[0].a()
note = col.newNote()
note["Text"] = "hello {{c1::world::typical}}"
assert col.addNote(note) == 1
assert "<span class=cloze>[typical]</span>" in note.cards()[0].q()
assert "<span class=cloze>world</span>" in note.cards()[0].a()
# and with 2 clozes
f = d.newNote()
f["Text"] = "hello {{c1::world}} {{c2::bar}}"
assert d.addNote(f) == 2
(c1, c2) = f.cards()
note = col.newNote()
note["Text"] = "hello {{c1::world}} {{c2::bar}}"
assert col.addNote(note) == 2
(c1, c2) = note.cards()
assert "<span class=cloze>[...]</span> bar" in c1.q()
assert "<span class=cloze>world</span> bar" in c1.a()
assert "world <span class=cloze>[...]</span>" in c2.q()
assert "world <span class=cloze>bar</span>" in c2.a()
# if there are multiple answers for a single cloze, they are given in a
# list
f = d.newNote()
f["Text"] = "a {{c1::b}} {{c1::c}}"
assert d.addNote(f) == 1
assert "<span class=cloze>b</span> <span class=cloze>c</span>" in (f.cards()[0].a())
note = col.newNote()
note["Text"] = "a {{c1::b}} {{c1::c}}"
assert col.addNote(note) == 1
assert "<span class=cloze>b</span> <span class=cloze>c</span>" in (
note.cards()[0].a()
)
# if we add another cloze, a card should be generated
cnt = d.cardCount()
f["Text"] = "{{c2::hello}} {{c1::foo}}"
f.flush()
assert d.cardCount() == cnt + 1
cnt = col.cardCount()
note["Text"] = "{{c2::hello}} {{c1::foo}}"
note.flush()
assert col.cardCount() == cnt + 1
# 0 or negative indices are not supported
f["Text"] += "{{c0::zero}} {{c-1:foo}}"
f.flush()
assert len(f.cards()) == 2
note["Text"] += "{{c0::zero}} {{c-1:foo}}"
note.flush()
assert len(note.cards()) == 2
def test_cloze_mathjax():
d = getEmptyCol()
d.models.setCurrent(d.models.byName("Cloze"))
f = d.newNote()
f[
col = getEmptyCol()
col.models.setCurrent(col.models.byName("Cloze"))
note = col.newNote()
note[
"Text"
] = r"{{c1::ok}} \(2^2\) {{c2::not ok}} \(2^{{c3::2}}\) \(x^3\) {{c4::blah}} {{c5::text with \(x^2\) jax}}"
assert d.addNote(f)
assert len(f.cards()) == 5
assert "class=cloze" in f.cards()[0].q()
assert "class=cloze" in f.cards()[1].q()
assert "class=cloze" not in f.cards()[2].q()
assert "class=cloze" in f.cards()[3].q()
assert "class=cloze" in f.cards()[4].q()
assert col.addNote(note)
assert len(note.cards()) == 5
assert "class=cloze" in note.cards()[0].q()
assert "class=cloze" in note.cards()[1].q()
assert "class=cloze" not in note.cards()[2].q()
assert "class=cloze" in note.cards()[3].q()
assert "class=cloze" in note.cards()[4].q()
f = d.newNote()
f["Text"] = r"\(a\) {{c1::b}} \[ {{c1::c}} \]"
assert d.addNote(f)
assert len(f.cards()) == 1
note = col.newNote()
note["Text"] = r"\(a\) {{c1::b}} \[ {{c1::c}} \]"
assert col.addNote(note)
assert len(note.cards()) == 1
assert (
f.cards()[0].q().endswith(r"\(a\) <span class=cloze>[...]</span> \[ [...] \]")
note.cards()[0]
.q()
.endswith(r"\(a\) <span class=cloze>[...]</span> \[ [...] \]")
)
def test_typecloze():
d = getEmptyCol()
m = d.models.byName("Cloze")
d.models.setCurrent(m)
col = getEmptyCol()
m = col.models.byName("Cloze")
col.models.setCurrent(m)
m["tmpls"][0]["qfmt"] = "{{cloze:Text}}{{type:cloze:Text}}"
d.models.save(m)
f = d.newNote()
f["Text"] = "hello {{c1::world}}"
d.addNote(f)
assert "[[type:cloze:Text]]" in f.cards()[0].q()
col.models.save(m)
note = col.newNote()
note["Text"] = "hello {{c1::world}}"
col.addNote(note)
assert "[[type:cloze:Text]]" in note.cards()[0].q()
def test_chained_mods():
d = getEmptyCol()
d.models.setCurrent(d.models.byName("Cloze"))
m = d.models.current()
mm = d.models
col = getEmptyCol()
col.models.setCurrent(col.models.byName("Cloze"))
m = col.models.current()
mm = col.models
# We replace the default Cloze template
t = mm.newTemplate("ChainedCloze")
@ -249,76 +255,76 @@ def test_chained_mods():
t["afmt"] = "{{cloze:text:Text}}"
mm.addTemplate(m, t)
mm.save(m)
d.models.remTemplate(m, m["tmpls"][0])
col.models.remTemplate(m, m["tmpls"][0])
f = d.newNote()
note = col.newNote()
q1 = '<span style="color:red">phrase</span>'
a1 = "<b>sentence</b>"
q2 = '<span style="color:red">en chaine</span>'
a2 = "<i>chained</i>"
f["Text"] = "This {{c1::%s::%s}} demonstrates {{c1::%s::%s}} clozes." % (
note["Text"] = "This {{c1::%s::%s}} demonstrates {{c1::%s::%s}} clozes." % (
q1,
a1,
q2,
a2,
)
assert d.addNote(f) == 1
assert col.addNote(note) == 1
assert (
"This <span class=cloze>[sentence]</span> demonstrates <span class=cloze>[chained]</span> clozes."
in f.cards()[0].q()
in note.cards()[0].q()
)
assert (
"This <span class=cloze>phrase</span> demonstrates <span class=cloze>en chaine</span> clozes."
in f.cards()[0].a()
in note.cards()[0].a()
)
def test_modelChange():
deck = getEmptyCol()
cloze = deck.models.byName("Cloze")
col = getEmptyCol()
cloze = col.models.byName("Cloze")
# enable second template and add a note
m = deck.models.current()
mm = deck.models
m = col.models.current()
mm = col.models
t = mm.newTemplate("Reverse")
t["qfmt"] = "{{Back}}"
t["afmt"] = "{{Front}}"
mm.addTemplate(m, t)
mm.save(m)
basic = m
f = deck.newNote()
f["Front"] = "f"
f["Back"] = "b123"
deck.addNote(f)
note = col.newNote()
note["Front"] = "note"
note["Back"] = "b123"
col.addNote(note)
# switch fields
map = {0: 1, 1: 0}
deck.models.change(basic, [f.id], basic, map, None)
f.load()
assert f["Front"] == "b123"
assert f["Back"] == "f"
col.models.change(basic, [note.id], basic, map, None)
note.load()
assert note["Front"] == "b123"
assert note["Back"] == "note"
# switch cards
c0 = f.cards()[0]
c1 = f.cards()[1]
c0 = note.cards()[0]
c1 = note.cards()[1]
assert "b123" in c0.q()
assert "f" in c1.q()
assert "note" in c1.q()
assert c0.ord == 0
assert c1.ord == 1
deck.models.change(basic, [f.id], basic, None, map)
f.load()
col.models.change(basic, [note.id], basic, None, map)
note.load()
c0.load()
c1.load()
assert "f" in c0.q()
assert "note" in c0.q()
assert "b123" in c1.q()
assert c0.ord == 1
assert c1.ord == 0
# .cards() returns cards in order
assert f.cards()[0].id == c1.id
assert note.cards()[0].id == c1.id
# delete first card
map = {0: None, 1: 1}
if isWin:
# The low precision timer on Windows reveals a race condition
time.sleep(0.05)
deck.models.change(basic, [f.id], basic, None, map)
f.load()
col.models.change(basic, [note.id], basic, None, map)
note.load()
c0.load()
# the card was deleted
try:
@ -327,33 +333,33 @@ def test_modelChange():
except NotFoundError:
pass
# but we have two cards, as a new one was generated
assert len(f.cards()) == 2
assert len(note.cards()) == 2
# an unmapped field becomes blank
assert f["Front"] == "b123"
assert f["Back"] == "f"
deck.models.change(basic, [f.id], basic, map, None)
f.load()
assert f["Front"] == ""
assert f["Back"] == "f"
assert note["Front"] == "b123"
assert note["Back"] == "note"
col.models.change(basic, [note.id], basic, map, None)
note.load()
assert note["Front"] == ""
assert note["Back"] == "note"
# another note to try model conversion
f = deck.newNote()
f["Front"] = "f2"
f["Back"] = "b2"
deck.addNote(f)
counts = deck.models.all_use_counts()
note = col.newNote()
note["Front"] = "f2"
note["Back"] = "b2"
col.addNote(note)
counts = col.models.all_use_counts()
assert next(c.use_count for c in counts if c.name == "Basic") == 2
assert next(c.use_count for c in counts if c.name == "Cloze") == 0
map = {0: 0, 1: 1}
deck.models.change(basic, [f.id], cloze, map, map)
f.load()
assert f["Text"] == "f2"
assert len(f.cards()) == 2
col.models.change(basic, [note.id], cloze, map, map)
note.load()
assert note["Text"] == "f2"
assert len(note.cards()) == 2
# back the other way, with deletion of second ord
deck.models.remTemplate(basic, basic["tmpls"][1])
assert deck.db.scalar("select count() from cards where nid = ?", f.id) == 2
col.models.remTemplate(basic, basic["tmpls"][1])
assert col.db.scalar("select count() from cards where nid = ?", note.id) == 2
map = {0: 0}
deck.models.change(cloze, [f.id], basic, map, map)
assert deck.db.scalar("select count() from cards where nid = ?", f.id) == 1
col.models.change(cloze, [note.id], basic, map, map)
assert col.db.scalar("select count() from cards where nid = ?", note.id) == 1
def test_req():
@ -362,8 +368,8 @@ def test_req():
return
assert len(model["tmpls"]) == len(model["req"])
d = getEmptyCol()
mm = d.models
col = getEmptyCol()
mm = col.models
basic = mm.byName("Basic")
assert "req" in basic
reqSize(basic)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -8,30 +8,30 @@ from tests.shared import getEmptyCol
def test_stats():
d = getEmptyCol()
f = d.newNote()
f["Front"] = "foo"
d.addNote(f)
c = f.cards()[0]
col = getEmptyCol()
note = col.newNote()
note["Front"] = "foo"
col.addNote(note)
c = note.cards()[0]
# card stats
assert d.cardStats(c)
d.reset()
c = d.sched.getCard()
d.sched.answerCard(c, 3)
d.sched.answerCard(c, 2)
assert d.cardStats(c)
assert col.cardStats(c)
col.reset()
c = col.sched.getCard()
col.sched.answerCard(c, 3)
col.sched.answerCard(c, 2)
assert col.cardStats(c)
def test_graphs_empty():
d = getEmptyCol()
assert d.stats().report()
col = getEmptyCol()
assert col.stats().report()
def test_graphs():
dir = tempfile.gettempdir()
d = getEmptyCol()
g = d.stats()
col = getEmptyCol()
g = col.stats()
rep = g.report()
with open(os.path.join(dir, "test.html"), "w", encoding="UTF-8") as f:
f.write(rep)
with open(os.path.join(dir, "test.html"), "w", encoding="UTF-8") as note:
note.write(rep)
return

View file

@ -2,14 +2,14 @@ from tests.shared import getEmptyCol
def test_deferred_frontside():
d = getEmptyCol()
m = d.models.current()
col = getEmptyCol()
m = col.models.current()
m["tmpls"][0]["qfmt"] = "{{custom:Front}}"
d.models.save(m)
col.models.save(m)
f = d.newNote()
f["Front"] = "xxtest"
f["Back"] = ""
d.addNote(f)
note = col.newNote()
note["Front"] = "xxtest"
note["Back"] = ""
col.addNote(note)
assert "xxtest" in f.cards()[0].a()
assert "xxtest" in note.cards()[0].a()

View file

@ -13,84 +13,84 @@ def getEmptyCol():
def test_op():
d = getEmptyCol()
col = getEmptyCol()
# should have no undo by default
assert not d.undoName()
assert not col.undoName()
# let's adjust a study option
d.save("studyopts")
d.conf["abc"] = 5
col.save("studyopts")
col.conf["abc"] = 5
# it should be listed as undoable
assert d.undoName() == "studyopts"
assert col.undoName() == "studyopts"
# with about 5 minutes until it's clobbered
assert time.time() - d._lastSave < 1
assert time.time() - col._lastSave < 1
# undoing should restore the old value
d.undo()
assert not d.undoName()
assert "abc" not in d.conf
col.undo()
assert not col.undoName()
assert "abc" not in col.conf
# an (auto)save will clear the undo
d.save("foo")
assert d.undoName() == "foo"
d.save()
assert not d.undoName()
col.save("foo")
assert col.undoName() == "foo"
col.save()
assert not col.undoName()
# and a review will, too
d.save("add")
f = d.newNote()
f["Front"] = "one"
d.addNote(f)
d.reset()
assert d.undoName() == "add"
c = d.sched.getCard()
d.sched.answerCard(c, 2)
assert d.undoName() == "Review"
col.save("add")
note = col.newNote()
note["Front"] = "one"
col.addNote(note)
col.reset()
assert col.undoName() == "add"
c = col.sched.getCard()
col.sched.answerCard(c, 2)
assert col.undoName() == "Review"
def test_review():
d = getEmptyCol()
d.conf["counts"] = COUNT_REMAINING
f = d.newNote()
f["Front"] = "one"
d.addNote(f)
d.reset()
assert not d.undoName()
col = getEmptyCol()
col.conf["counts"] = COUNT_REMAINING
note = col.newNote()
note["Front"] = "one"
col.addNote(note)
col.reset()
assert not col.undoName()
# answer
assert d.sched.counts() == (1, 0, 0)
c = d.sched.getCard()
assert col.sched.counts() == (1, 0, 0)
c = col.sched.getCard()
assert c.queue == QUEUE_TYPE_NEW
d.sched.answerCard(c, 3)
col.sched.answerCard(c, 3)
assert c.left == 1001
assert d.sched.counts() == (0, 1, 0)
assert col.sched.counts() == (0, 1, 0)
assert c.queue == QUEUE_TYPE_LRN
# undo
assert d.undoName()
d.undo()
d.reset()
assert d.sched.counts() == (1, 0, 0)
assert col.undoName()
col.undo()
col.reset()
assert col.sched.counts() == (1, 0, 0)
c.load()
assert c.queue == QUEUE_TYPE_NEW
assert c.left != 1001
assert not d.undoName()
assert not col.undoName()
# we should be able to undo multiple answers too
f = d.newNote()
f["Front"] = "two"
d.addNote(f)
d.reset()
assert d.sched.counts() == (2, 0, 0)
c = d.sched.getCard()
d.sched.answerCard(c, 3)
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert d.sched.counts() == (0, 2, 0)
d.undo()
d.reset()
assert d.sched.counts() == (1, 1, 0)
d.undo()
d.reset()
assert d.sched.counts() == (2, 0, 0)
note = col.newNote()
note["Front"] = "two"
col.addNote(note)
col.reset()
assert col.sched.counts() == (2, 0, 0)
c = col.sched.getCard()
col.sched.answerCard(c, 3)
c = col.sched.getCard()
col.sched.answerCard(c, 3)
assert col.sched.counts() == (0, 2, 0)
col.undo()
col.reset()
assert col.sched.counts() == (1, 1, 0)
col.undo()
col.reset()
assert col.sched.counts() == (2, 0, 0)
# performing a normal op will clear the review queue
c = d.sched.getCard()
d.sched.answerCard(c, 3)
assert d.undoName() == "Review"
d.save("foo")
assert d.undoName() == "foo"
d.undo()
assert not d.undoName()
c = col.sched.getCard()
col.sched.answerCard(c, 3)
assert col.undoName() == "Review"
col.save("foo")
assert col.undoName() == "foo"
col.undo()
assert not col.undoName()