# coding: utf-8
import nose, os, re
from tests.shared import assertException
from anki.errors import *
from anki import DeckStorage
from anki.db import *
from anki.models import FieldModel, Model, CardModel
from anki.stdmodels import BasicModel
from anki.utils import stripHTML
newPath = None
newModified = None
testDir = os.path.dirname(__file__)
## opening/closing
def test_new():
deck = DeckStorage.Deck()
assert not deck.path
assert deck.engine
assert deck.modified
def test_attachNew():
global newPath, newModified
path = "/tmp/test_attachNew.anki"
try:
os.unlink(path)
except OSError:
pass
deck = DeckStorage.Deck(path)
# for attachOld()
newPath = deck.path
deck.setVar("pageSize", 4096)
deck.save()
newModified = deck.modified
deck.close()
del deck
def test_attachOld():
deck = DeckStorage.Deck(newPath, backup=False)
assert deck.modified == newModified
deck.close()
def test_attachReadOnly():
# non-writeable dir
assertException(Exception,
lambda: DeckStorage.Deck("/attachroot"))
# reuse tmp file from before, test non-writeable file
os.chmod(newPath, 0)
assertException(Exception,
lambda: DeckStorage.Deck(newPath))
os.chmod(newPath, 0666)
os.unlink(newPath)
def test_saveAs():
path = "/tmp/test_saveAs.anki"
try:
os.unlink(path)
except OSError:
pass
path2 = "/tmp/test_saveAs2.anki"
try:
os.unlink(path2)
except OSError:
pass
# start with an in-memory deck
deck = DeckStorage.Deck()
deck.addModel(BasicModel())
# add a card
f = deck.newFact()
f['Front'] = u"foo"; f['Back'] = u"bar"
deck.addFact(f)
assert deck.cardCount == 1
# save in new deck
newDeck = deck.saveAs(path)
assert newDeck.cardCount == 1
# delete card
id = newDeck.s.scalar("select id from cards")
newDeck.deleteCard(id)
# save into new deck
newDeck2 = newDeck.saveAs(path2)
# new deck should have zero cards
assert newDeck2.cardCount == 0
# but old deck should have reverted the unsaved changes
newDeck = DeckStorage.Deck(path)
assert newDeck.cardCount == 1
newDeck.close()
def test_factAddDelete():
deck = DeckStorage.Deck()
deck.addModel(BasicModel())
# set rollback point
deck.s.commit()
f = deck.newFact()
# empty fields
try:
deck.addFact(f)
except Exception, e:
pass
assert e.data['type'] == 'fieldEmpty'
# add a fact
f['Front'] = u"one"; f['Back'] = u"two"
f = deck.addFact(f)
assert len(f.cards) == 1
deck.rollback()
# try with two cards
f = deck.newFact()
f['Front'] = u"one"; f['Back'] = u"two"
f.model.cardModels[1].active = True
f = deck.addFact(f)
assert len(f.cards) == 2
# ensure correct order
c0 = [c for c in f.cards if c.ordinal == 0][0]
assert re.sub("?.+?>", "", c0.question) == u"one"
# now let's make a duplicate
f2 = deck.newFact()
f2['Front'] = u"one"; f2['Back'] = u"three"
try:
f2 = deck.addFact(f2)
except Exception, e:
pass
assert e.data['type'] == 'fieldNotUnique'
# try delete the first card
id1 = f.cards[0].id; id2 = f.cards[1].id
deck.deleteCard(id1)
# and the second should clear the fact
deck.deleteCard(id2)
def test_modelAddDelete():
deck = DeckStorage.Deck()
deck.addModel(BasicModel())
deck.addModel(BasicModel())
f = deck.newFact()
f['Front'] = u'1'
f['Back'] = u'2'
deck.addFact(f)
assert deck.cardCount == 1
deck.deleteModel(deck.currentModel)
deck.reset()
assert deck.cardCount == 0
deck.s.refresh(deck)
def test_modelCopy():
deck = DeckStorage.Deck()
m = BasicModel()
assert len(m.fieldModels) == 2
assert len(m.cardModels) == 2
deck.addModel(m)
f = deck.newFact()
f['Front'] = u'1'
deck.addFact(f)
m2 = deck.copyModel(m)
assert m2.name == "Basic copy"
assert m2.id != m.id
assert m2.fieldModels[0].id != m.fieldModels[0].id
assert m2.cardModels[0].id != m.cardModels[0].id
assert len(m2.fieldModels) == 2
assert len(m.fieldModels) == 2
assert len(m2.fieldModels) == len(m.fieldModels)
assert len(m.cardModels) == 2
assert len(m2.cardModels) == 2
def test_media():
deck = DeckStorage.Deck()
# create a media dir
deck.mediaDir(create=True)
# put a file into it
file = unicode(os.path.join(testDir, "deck/fake.png"))
deck.addMedia(file)
# make sure it gets copied on saveas
path = "/tmp/saveAs2.anki"
sum = "fake.png"
try:
os.unlink(path)
except OSError:
pass
deck.saveAs(path)
assert os.path.exists("/tmp/saveAs2.media/%s" % sum)
def test_modelChange():
deck = DeckStorage.Deck()
m = Model(u"Japanese")
m1 = m
f = FieldModel(u'Expression', True, True)
m.addFieldModel(f)
m.addFieldModel(FieldModel(u'Meaning', False, False))
f = FieldModel(u'Reading', False, False)
m.addFieldModel(f)
m.addCardModel(CardModel(u"Recognition",
u"%(Expression)s",
u"%(Reading)s
%(Meaning)s"))
m.addCardModel(CardModel(u"Recall",
u"%(Meaning)s",
u"%(Expression)s
%(Reading)s",
active=False))
m.tags = u"Japanese"
m1.cardModels[1].active = True
deck.addModel(m1)
f = deck.newFact()
f['Expression'] = u'e'
f['Meaning'] = u'm'
f['Reading'] = u'r'
f = deck.addFact(f)
f2 = deck.newFact()
f2['Expression'] = u'e2'
f2['Meaning'] = u'm2'
f2['Reading'] = u'r2'
deck.addFact(f2)
m2 = BasicModel()
m2.cardModels[1].active = True
deck.addModel(m2)
# convert to basic
assert deck.modelUseCount(m1) == 2
assert deck.modelUseCount(m2) == 0
assert deck.cardCount == 4
assert deck.factCount == 2
fmap = {m1.fieldModels[0]: m2.fieldModels[0],
m1.fieldModels[1]: None,
m1.fieldModels[2]: m2.fieldModels[1]}
cmap = {m1.cardModels[0]: m2.cardModels[0],
m1.cardModels[1]: None}
deck.changeModel([f.id], m2, fmap, cmap)
deck.reset()
assert deck.modelUseCount(m1) == 1
assert deck.modelUseCount(m2) == 1
assert deck.cardCount == 3
assert deck.factCount == 2
(q, a) = deck.s.first("""
select question, answer from cards where factId = :id""",
id=f.id)
assert stripHTML(q) == u"e"
assert stripHTML(a) == u"r"
def test_findCards():
deck = DeckStorage.Deck()
deck.addModel(BasicModel())
f = deck.newFact()
f['Front'] = u'dog'
f['Back'] = u'cat'
f.tags = u"monkey"
deck.addFact(f)
f = deck.newFact()
f['Front'] = u'goats are fun'
f['Back'] = u'sheep'
f.tags = u"sheep goat horse"
deck.addFact(f)
f = deck.newFact()
f['Front'] = u'cat'
f['Back'] = u'sheep'
deck.addFact(f)
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")) == 2
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
# make sure card templates and models match too
assert len(deck.findCards('tag:basic')) == 3
assert len(deck.findCards('tag:forward')) == 3
deck.addModel(BasicModel())
f = deck.newFact()
f['Front'] = u'foo'
f['Back'] = u'bar'
deck.addFact(f)
deck.currentModel.cardModels[1].active = True
f = deck.newFact()
f['Front'] = u'baz'
f['Back'] = u'qux'
c = deck.addFact(f)
assert len(deck.findCards('tag:forward')) == 5
assert len(deck.findCards('tag:reverse')) == 1