mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 06:52:21 -04:00

As per the forum thread, the current due counts are really demotivating when there's a backlog of cards. In attempt to solve this, I'm trying out a new behaviour as the default: instead of reporting all the due cards including the backlog, the status bar will show an increasing count of cards studied that day. Theoretically this should allow users to focus on what they've done rather than what they have to do. The old behaviour is still there as an option.
216 lines
6.5 KiB
Python
216 lines
6.5 KiB
Python
# coding: utf-8
|
|
|
|
import os, re, datetime
|
|
from tests.shared import assertException, getEmptyDeck, testDir
|
|
from anki.stdmodels import addBasicModel
|
|
from anki.consts import *
|
|
|
|
from anki import Deck
|
|
|
|
newPath = None
|
|
newMod = None
|
|
|
|
def test_create():
|
|
global newPath, newMod
|
|
path = "/tmp/test_attachNew.anki"
|
|
try:
|
|
os.unlink(path)
|
|
except OSError:
|
|
pass
|
|
deck = Deck(path)
|
|
# for open()
|
|
newPath = deck.path
|
|
deck.save()
|
|
newMod = deck.mod
|
|
deck.close()
|
|
del deck
|
|
|
|
def test_open():
|
|
deck = Deck(newPath)
|
|
assert deck.mod == newMod
|
|
deck.close()
|
|
|
|
def test_openReadOnly():
|
|
# non-writeable dir
|
|
assertException(Exception,
|
|
lambda: Deck("/attachroot"))
|
|
# reuse tmp file from before, test non-writeable file
|
|
os.chmod(newPath, 0)
|
|
assertException(Exception,
|
|
lambda: Deck(newPath))
|
|
os.chmod(newPath, 0666)
|
|
os.unlink(newPath)
|
|
|
|
def test_factAddDelete():
|
|
deck = getEmptyDeck()
|
|
# add a fact
|
|
f = deck.newFact()
|
|
f['Front'] = u"one"; f['Back'] = u"two"
|
|
n = deck.addFact(f)
|
|
assert n == 1
|
|
deck.rollback()
|
|
assert deck.cardCount() == 0
|
|
# try with two cards
|
|
f = deck.newFact()
|
|
f['Front'] = u"one"; f['Back'] = u"two"
|
|
m = f.model()
|
|
m['tmpls'][1]['actv'] = True
|
|
deck.models.save(m)
|
|
n = deck.addFact(f)
|
|
assert n == 2
|
|
# check q/a generation
|
|
c0 = f.cards()[0]
|
|
assert re.sub("</?.+?>", "", c0.q()) == u"one"
|
|
# it should not be a duplicate
|
|
for p in f.problems():
|
|
assert not p
|
|
# now let's make a duplicate and test uniqueness
|
|
f2 = deck.newFact()
|
|
f2.model()['flds'][1]['req'] = True
|
|
f2['Front'] = u"one"; f2['Back'] = u""
|
|
p = f2.problems()
|
|
assert p[0] == "unique"
|
|
assert p[1] == "required"
|
|
# try delete the first card
|
|
cards = f.cards()
|
|
id1 = cards[0].id; id2 = cards[1].id
|
|
assert deck.cardCount() == 2
|
|
assert deck.factCount() == 1
|
|
deck.remCards([id1])
|
|
assert deck.cardCount() == 1
|
|
assert deck.factCount() == 1
|
|
# and the second should clear the fact
|
|
deck.remCards([id2])
|
|
assert deck.cardCount() == 0
|
|
assert deck.factCount() == 0
|
|
|
|
def test_fieldChecksum():
|
|
deck = getEmptyDeck()
|
|
f = deck.newFact()
|
|
f['Front'] = u"new"; f['Back'] = u"new2"
|
|
deck.addFact(f)
|
|
assert deck.db.scalar(
|
|
"select csum from fsums") == int("22af645d", 16)
|
|
# empty field should have no checksum
|
|
f['Front'] = u""
|
|
f.flush()
|
|
assert deck.db.scalar(
|
|
"select count() from fsums") == 0
|
|
# changing the val should change the checksum
|
|
f['Front'] = u"newx"
|
|
f.flush()
|
|
assert deck.db.scalar(
|
|
"select csum from fsums") == int("4b0e5a4c", 16)
|
|
# turning off unique and modifying the fact should delete the sum
|
|
m = f.model()
|
|
m['flds'][0]['uniq'] = False
|
|
deck.models.save(m)
|
|
f.flush()
|
|
assert deck.db.scalar(
|
|
"select count() from fsums") == 0
|
|
# and turning on both should ensure two checksums generated
|
|
m['flds'][0]['uniq'] = True
|
|
m['flds'][1]['uniq'] = True
|
|
deck.models.save(m)
|
|
f.flush()
|
|
assert deck.db.scalar(
|
|
"select count() from fsums") == 2
|
|
|
|
def test_upgrade():
|
|
import tempfile, shutil
|
|
src = os.path.join(testDir, "support", "anki12.anki")
|
|
(fd, dst) = tempfile.mkstemp(suffix=".anki")
|
|
print "upgrade to", dst
|
|
shutil.copy(src, dst)
|
|
deck = Deck(dst)
|
|
# creation time should have been adjusted
|
|
d = datetime.datetime.fromtimestamp(deck.crt)
|
|
assert d.hour == 4 and d.minute == 0
|
|
# 3 new, 2 failed, 1 due
|
|
deck.conf['counts'] = COUNT_REMAINING
|
|
assert deck.sched.counts() == (3,2,1)
|
|
# now's a good time to test the integrity check too
|
|
deck.fixIntegrity()
|
|
|
|
def test_groups():
|
|
deck = getEmptyDeck()
|
|
# we start with a standard group
|
|
assert len(deck.groups.groups) == 1
|
|
# it should have an id of 1
|
|
assert deck.groups.name(1)
|
|
# create a new group
|
|
parentId = deck.groups.id("new group")
|
|
assert parentId
|
|
assert len(deck.groups.groups) == 2
|
|
# should get the same id
|
|
assert deck.groups.id("new group") == parentId
|
|
# by default, everything should be shown
|
|
assert not deck.groups.selected()
|
|
assert not deck.groups.active()
|
|
# and the default group is used
|
|
assert deck.groups.top()['id'] == 1
|
|
# we can select the default explicitly
|
|
deck.groups.select(1)
|
|
assert deck.groups.selected() == 1
|
|
assert deck.groups.active() == [1]
|
|
assert deck.groups.top()['id'] == 1
|
|
# let's create a child and select that
|
|
childId = deck.groups.id("new group::child")
|
|
deck.groups.select(childId)
|
|
assert deck.groups.selected() == childId
|
|
assert deck.groups.active() == [childId]
|
|
assert deck.groups.top()['id'] == parentId
|
|
# if we select the parent, the child gets included
|
|
deck.groups.select(parentId)
|
|
assert sorted(deck.groups.active()) == [parentId, childId]
|
|
|
|
def test_selective():
|
|
deck = getEmptyDeck()
|
|
f = deck.newFact()
|
|
f['Front'] = u"1"; f.tags = ["one", "three"]
|
|
deck.addFact(f)
|
|
f = deck.newFact()
|
|
f['Front'] = u"2"; f.tags = ["two", "three", "four"]
|
|
deck.addFact(f)
|
|
f = deck.newFact()
|
|
f['Front'] = u"3"; f.tags = ["one", "two", "three", "four"]
|
|
deck.addFact(f)
|
|
assert len(deck.tags.selTagFids(["one"], [])) == 2
|
|
assert len(deck.tags.selTagFids(["three"], [])) == 3
|
|
assert len(deck.tags.selTagFids([], ["three"])) == 0
|
|
assert len(deck.tags.selTagFids(["one"], ["three"])) == 0
|
|
assert len(deck.tags.selTagFids(["one"], ["two"])) == 1
|
|
assert len(deck.tags.selTagFids(["two", "three"], [])) == 3
|
|
assert len(deck.tags.selTagFids(["two", "three"], ["one"])) == 1
|
|
assert len(deck.tags.selTagFids(["one", "three"], ["two", "four"])) == 1
|
|
deck.tags.setGroupForTags(["three"], [], 3)
|
|
assert deck.db.scalar("select count() from cards where gid = 3") == 3
|
|
deck.tags.setGroupForTags(["one"], [], 2)
|
|
assert deck.db.scalar("select count() from cards where gid = 2") == 2
|
|
|
|
def test_addDelTags():
|
|
deck = getEmptyDeck()
|
|
f = deck.newFact()
|
|
f['Front'] = u"1"
|
|
deck.addFact(f)
|
|
f2 = deck.newFact()
|
|
f2['Front'] = u"2"
|
|
deck.addFact(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 = getEmptyDeck()
|
|
assert len(deck.models.models) == 2
|
|
for i in range(100):
|
|
addBasicModel(deck)
|
|
assert len(deck.models.models) == 102
|
|
|