Anki/tests/test_media.py
Damien Elmes c59dd854fb add change detection
I removed the media database in an earlier commit, but it's now necessary
again as I decided to add native media syncing to AnkiWeb.

This time, the DB is stored in the media folder rather than with the deck.
This means we avoid sending it in a full sync, and makes deck backups faster.
The DB is a cache of file modtimes and checksums. When findChanges() is
called, the code checks to see which files were added, changed or deleted
since the last time, and updates the log of changes. Because the scanning step
and log retrieval is separate, it's possible to do the scanning in the
background if the need arises.

If the DB is deleted by the user, Anki will forget any deletions, and add all
the files back to the DB the next time it's accessed.

File changes are recorded as a delete + add.

media.addFile() could be optimized in the future to log media added manually
by the user, allowing us to skip the full directory scan in cases where the
only changes were manually added media.
2011-09-12 03:11:06 +09:00

98 lines
3.2 KiB
Python

# coding: utf-8
import tempfile, os, time
from anki import Deck
from anki.utils import checksum
from shared import getEmptyDeck, testDir
# copying files to media folder
def test_add():
d = getEmptyDeck()
dir = tempfile.mkdtemp(prefix="anki")
path = os.path.join(dir, "foo.jpg")
open(path, "w").write("hello")
# new file, should preserve name
assert d.media.addFile(path) == "foo.jpg"
# adding the same file again should not create a duplicate
assert d.media.addFile(path) == "foo.jpg"
# but if it has a different md5, it should
open(path, "w").write("world")
assert d.media.addFile(path) == "foo (1).jpg"
def test_strings():
d = getEmptyDeck()
mf = d.media.mediaFiles
assert mf("aoeu") == []
assert mf("aoeu<img src='foo.jpg'>ao") == ["foo.jpg"]
assert mf("aoeu<img src=foo bar.jpg>ao") == ["foo bar.jpg"]
assert mf("aoeu<img src=\"foo.jpg\">ao") == ["foo.jpg"]
assert mf("aoeu<img src=\"foo.jpg\"><img class=yo src=fo>ao") == [
"foo.jpg", "fo"]
assert mf("aou[sound:foo.mp3]aou") == ["foo.mp3"]
sp = d.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
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 = getEmptyDeck()
# create a media dir
d.media.dir()
# put a file into it
file = unicode(os.path.join(testDir, "support/fake.png"))
d.media.addFile(file)
# add a fact which references it
f = d.newFact()
f['Front'] = u"one"; f['Back'] = u"<img src='fake.png'>"
d.addFact(f)
# and one which references a non-existent file
f = d.newFact()
f['Front'] = u"one"; f['Back'] = u"<img src='fake2.png'>"
d.addFact(f)
# and add another file which isn't used
open(os.path.join(d.media.dir(), "foo.jpg"), "wb").write("test")
# check media
ret = d.media.check()
assert ret[0] == ["fake2.png"]
assert ret[1] == ["foo.jpg"]
def test_changes():
d = getEmptyDeck()
assert d.media.changed()
add, rem = d.media.changesSince(0)
assert not add; assert not rem
assert not d.media.changed()
# add a file
dir = tempfile.mkdtemp(prefix="anki")
path = os.path.join(dir, "foo.jpg")
open(path, "w").write("hello")
time.sleep(1)
path = d.media.addFile(path)
# should have been logged
add, rem = d.media.changesSince(0)
assert add; assert not rem
mod = add[0][1]
# if we modify it, the cache won't notice
time.sleep(1)
open(path, "w").write("world")
add, rem = d.media.changesSince(0)
assert len(add) == 1
# but if we add another file, it will
time.sleep(1)
open(path+"2", "w").write("yo")
add, rem = d.media.changesSince(0)
assert len(add) == 2
assert len(rem) == 1
assert add[0][1] != mod
assert add[0][0] == "foo.jpg"
# deletions should get noticed too
time.sleep(1)
os.unlink(path+"2")
add, rem = d.media.changesSince(0)
assert len(add) == 2
assert len(rem) == 2