Merged revisions 770-771 via svnmerge from
[joel/kofoto.git] / src / test / shelftests.py
1 #! /usr/bin/env python
2
3 import gc
4 import os
5 import shutil
6 import sys
7 import threading
8 import unittest
9 import Image as PILImage
10
11 if __name__ == "__main__":
12     cwd = os.getcwd()
13     libdir = unicode(os.path.realpath(
14         os.path.join(os.path.dirname(sys.argv[0]), "..", "lib")))
15     os.chdir(libdir)
16     sys.path.insert(0, libdir)
17 from kofoto.shelf import *
18
19 PICDIR = unicode(os.path.realpath(
20     os.path.join("..", "reference_pictures", "working")))
21
22 ######################################################################
23
24 db = "shelf.tmp"
25 codeset = "latin1"
26
27 def removeTmpDb():
28     for x in [db, db + "-journal"]:
29         if os.path.exists(x):
30             os.unlink(x)
31
32 class LockerThread(threading.Thread):
33     def __init__(self, mContinue, ltContinue):
34         threading.Thread.__init__(self)
35         self.mContinue = mContinue
36         self.ltContinue = ltContinue
37
38     def run(self):
39         s = Shelf(db, codeset)
40         s.create()
41         s.begin()
42         self.mContinue.set()
43         self.ltContinue.wait()
44         s.rollback()
45
46 ######################################################################
47
48 class TestPublicShelfFunctions(unittest.TestCase):
49     def test_computeImageHash(self):
50         s = computeImageHash(os.path.join(PICDIR, "arlaharen.png"))
51         assert s == "39a1266d2689f53d48b09a5e0ca0af1f"
52         try:
53             computeImageHash("nonexisting")
54         except IOError:
55             pass
56         else:
57             assert False, s
58
59     def test_verifyValidAlbumTag(self):
60         # Valid tags.
61         for x in ("foo", "1foo", "and", "exactly", "not", "or"):
62             try:
63                 verifyValidAlbumTag(x)
64             except:
65                 assert False, x
66         # Invalid tags.
67         for x in (None, 1, 1L, "1" "foo " "@foo"):
68             try:
69                 verifyValidAlbumTag(x)
70             except BadAlbumTagError:
71                 pass
72             else:
73                 assert False, x
74
75     def test_verifyValidCategoryTag(self):
76         # Valid tags.
77         for x in ("foo", "1foo"):
78             try:
79                 verifyValidCategoryTag(x)
80             except:
81                 assert False, x
82         # Invalid tags.
83         for x in (None, 1, 1L, "1" "foo " "@foo",
84                   "and", "exactly", "not", "or"):
85             try:
86                 verifyValidCategoryTag(x)
87             except BadCategoryTagError:
88                 pass
89             else:
90                 assert False, x
91
92     def test_makeValidTag(self):
93         for tag, validTag in [("", "_"),
94                               ("@", "_"),
95                               (" ", "_"),
96                               ("1", "1_"),
97                               ("@foo_", "foo_"),
98                               ("fo@o __", "fo@o__")]:
99             assert makeValidTag(tag) == validTag, (tag, validTag)
100
101 class TestNegativeShelfOpens(unittest.TestCase):
102     def tearDown(self):
103         removeTmpDb()
104
105     def test_NonexistingShelf(self):
106         try:
107             s = Shelf(db, codeset)
108             s.begin()
109         except ShelfNotFoundError:
110             pass
111         else:
112             assert False
113         assert not os.path.exists(db)
114
115     def test_BadShelf(self):
116         file(db, "w") # Create empty file.
117         try:
118             s = Shelf(db, codeset)
119             s.begin()
120         except UnsupportedShelfError:
121             pass
122         else:
123             assert False
124
125     def test_LockedShelf(self):
126         mContinue = threading.Event()
127         ltContinue = threading.Event()
128         lt = LockerThread(mContinue, ltContinue)
129         lt.start()
130         mContinue.wait()
131         try:
132             try:
133                 s = Shelf(db, codeset)
134                 s.begin()
135             except ShelfLockedError:
136                 pass
137             else:
138                 assert False
139         finally:
140             ltContinue.set()
141             lt.join()
142
143 class TestShelfCreation(unittest.TestCase):
144     def tearDown(self):
145         removeTmpDb()
146
147     def test_CreateShelf1(self):
148         s = Shelf(db, codeset)
149         s.create()
150         assert os.path.exists(db)
151
152     def test_CreateShelf2(self):
153         file(db, "w") # Create empty file.
154         s = Shelf(db, codeset)
155         try:
156             s.create()
157         except FailedWritingError:
158             pass
159         else:
160             assert False
161
162 class TestShelfMemoryLeakage(unittest.TestCase):
163     def tearDown(self):
164         removeTmpDb()
165
166     def test_MemoryLeak1(self):
167         s = Shelf(db, codeset)
168         s.create()
169         assert gc.collect() == 0
170
171     def test_MemoryLeak2(self):
172         s = Shelf(db, codeset)
173         s.create()
174         s.begin()
175         s.getObject(0)
176         s.rollback()
177         assert gc.collect() == 0
178
179     def test_MemoryLeak3(self):
180         s = Shelf(db, codeset)
181         s.create()
182         s.begin()
183         s.getObject(0)
184         s.commit()
185         assert gc.collect() == 0
186
187 class TestShelfTransactions(unittest.TestCase):
188     def tearDown(self):
189         removeTmpDb()
190
191     def test_commit(self):
192         s = Shelf(db, codeset)
193         s.create()
194         s.begin()
195         s.createAlbum(u"foo")
196         assert s.getAlbumByTag(u"foo")
197         s.commit()
198         s = Shelf(db, codeset)
199         s.begin()
200         assert s.getAlbumByTag(u"foo")
201         s.rollback()
202
203     def test_rollback(self):
204         s = Shelf(db, codeset)
205         s.create()
206         s.begin()
207         s.createAlbum(u"foo")
208         s.rollback()
209         s.begin()
210         try:
211             s.getAlbumByTag(u"foo")
212         except AlbumDoesNotExistError:
213             pass
214         else:
215             assert False
216
217     def test_isModified(self):
218         s = Shelf(db, codeset)
219         s.create()
220         s.begin()
221         assert not s.isModified()
222         s.createAlbum(u"foo")
223         assert s.isModified()
224         s.rollback()
225         s.begin()
226         assert not s.isModified()
227         s.rollback()
228
229     def test_registerModificationCallback(self):
230         res = [False]
231         def f(x):
232             res[0] = True
233         s = Shelf(db, codeset)
234         s.create()
235         s.begin()
236         s.registerModificationCallback(f)
237         assert not res[0]
238         s.createAlbum(u"foo")
239         assert res[0]
240         s.rollback()
241         res[0] = False
242         s.begin()
243         assert not res[0]
244         s.unregisterModificationCallback(f)
245         s.createAlbum(u"foo")
246         assert not res[0]
247         s.rollback()
248
249 class TestShelfFixture(unittest.TestCase):
250     def setUp(self):
251         self.shelf = Shelf(db, codeset)
252         self.shelf.create()
253         self.shelf.begin()
254         root = self.shelf.getRootAlbum()
255         alpha = self.shelf.createAlbum(u"alpha")
256         beta = self.shelf.createAlbum(u"beta")
257         children = [beta]
258         for x in os.listdir(PICDIR):
259             loc = os.path.join(PICDIR, x)
260             if not os.path.isfile(loc):
261                 continue
262             image = self.shelf.createImage()
263             imageversion = self.shelf.createImageVersion(
264                 image, loc, ImageVersionType.Original)
265             children.append(image)
266         del children[-1] # The last image becomes orphaned.
267         alpha.setChildren(children)
268         beta.setChildren(list(beta.getChildren()) + [children[-1]])
269         root.setChildren(list(root.getChildren()) + [alpha, beta])
270         self.shelf.createAlbum(u"epsilon", AlbumType.Plain) # Orphaned album.
271         zeta = self.shelf.createAlbum(u"zeta", AlbumType.Search)
272         zeta.setAttribute(u"query", u"a")
273         root.setChildren(list(root.getChildren()) + [zeta])
274
275         cat_a = self.shelf.createCategory(u"a", u"A")
276         cat_b = self.shelf.createCategory(u"b", u"B")
277         cat_c = self.shelf.createCategory(u"c", u"C")
278         cat_d = self.shelf.createCategory(u"d", u"D")
279         cat_a.connectChild(cat_b)
280         cat_a.connectChild(cat_c)
281         cat_b.connectChild(cat_d)
282         cat_c.connectChild(cat_d)
283
284         self.shelf.flushObjectCache()
285         self.shelf.flushCategoryCache()
286
287     def tearDown(self):
288         self.shelf.rollback()
289         removeTmpDb()
290
291 class TestShelfMethods(TestShelfFixture):
292     def test_flushCaches(self):
293         self.shelf.flushCategoryCache()
294         self.shelf.flushObjectCache()
295
296     def test_getStatistics(self):
297         s = self.shelf.getStatistics()
298         assert s["nalbums"] == 6
299         assert s["nimages"] == 11
300         assert s["nimageversions"] == 11
301
302     def test_createdObjects(self):
303         root = self.shelf.getRootAlbum()
304         children = list(root.getChildren())
305         assert len(children) == 4
306         orphans, alpha, beta, zeta = children
307         assert self.shelf.getAlbum(alpha.getId()) == alpha
308         assert self.shelf.getAlbumByTag(u"beta") == beta
309         assert len(list(alpha.getChildren())) == 11
310         assert len(list(beta.getChildren())) == 1
311
312     def test_createdAttributes(self):
313         imageversion = self.shelf.getImageVersionByLocation(
314             os.path.join(PICDIR, "Canon_Digital_IXUS.jpg"))
315         image = imageversion.getImage()
316         assert image.getAttribute(u"captured") == "2002-02-02 22:20:51"
317         assert image.getAttribute(u"cameramake") == "Canon"
318         assert image.getAttribute(u"cameramodel") == "Canon DIGITAL IXUS"
319
320     def test_negativeAlbumCreation(self):
321         try:
322             self.shelf.createAlbum(u"beta")
323         except AlbumExistsError:
324             pass
325         else:
326             assert False
327
328     def test_getAlbum(self):
329         album = self.shelf.getAlbum(0)
330         assert album == self.shelf.getRootAlbum()
331
332     def test_negativeGetAlbum(self):
333         try:
334             self.shelf.getAlbum(12345678)
335         except AlbumDoesNotExistError:
336             pass
337         else:
338             assert False
339
340     def test_getAlbumByTag(self):
341         album = self.shelf.getAlbumByTag(u"root")
342         assert album == self.shelf.getRootAlbum()
343
344     def test_negativeGetAlbumByTag(self):
345         try:
346             self.shelf.getAlbum(u"12345678")
347         except AlbumDoesNotExistError:
348             pass
349         else:
350             assert False
351
352     def test_getRootAlbum(self):
353         root = self.shelf.getRootAlbum()
354         assert root.getId() == 0
355         assert root == self.shelf.getAlbumByTag(u"root")
356
357     def test_getAllAlbums(self):
358         albums = list(self.shelf.getAllAlbums())
359         assert len(albums) == 6
360
361     def test_getAllImageVersions(self):
362         imageversions = list(self.shelf.getAllImageVersions())
363         assert len(imageversions) == 11
364
365     def test_getImageVersionsInDirectory(self):
366         imageversions = list(self.shelf.getImageVersionsInDirectory(u"."))
367         assert len(imageversions) == 0
368         imageversions = list(self.shelf.getImageVersionsInDirectory(PICDIR))
369         assert len(imageversions) == 11
370
371     def test_deleteAlbum(self):
372         album = self.shelf.getAlbumByTag(u"beta")
373         self.shelf.deleteAlbum(album.getId())
374
375     def test_negativeRootAlbumDeletion(self):
376         root = self.shelf.getRootAlbum()
377         try:
378             self.shelf.deleteAlbum(root.getId())
379         except UndeletableAlbumError:
380             pass
381         else:
382             assert False
383
384     def test_negativeAlbumDeletion(self):
385         try:
386             self.shelf.deleteAlbum(12345678)
387         except AlbumDoesNotExistError:
388             pass
389         else:
390             assert False
391
392     def test_negativeImageCreation(self):
393         try:
394             image = self.shelf.createImage()
395             self.shelf.createImageVersion(
396                 image,
397                 os.path.join(PICDIR, "arlaharen.png"),
398                 ImageVersionType.Original)
399         except ImageVersionExistsError:
400             pass
401         else:
402             assert False
403
404     def test_getImage(self):
405         imageversion = self.shelf.getImageVersionByLocation(
406             os.path.join(PICDIR, "arlaharen.png"))
407         image = imageversion.getImage()
408         assert self.shelf.getImage(image.getId()) == image
409
410     def test_negativeGetImage(self):
411         try:
412             self.shelf.getImage(12345678)
413         except ImageDoesNotExistError:
414             pass
415         else:
416             assert False
417
418     def test_getImageVersion(self):
419         imageversion = self.shelf.getImageVersionByLocation(
420             os.path.join(PICDIR, "arlaharen.png"))
421         assert self.shelf.getImageVersion(imageversion.getId()) == imageversion
422
423     def test_negativeGetImageVersion(self):
424         try:
425             self.shelf.getImageVersion(12345678)
426         except ImageVersionDoesNotExistError:
427             pass
428         else:
429             assert False
430
431     def test_getImageVersionByHash(self):
432         imageversion = self.shelf.getImageVersionByLocation(
433             os.path.join(PICDIR, "arlaharen.png"))
434         assert self.shelf.getImageVersionByHash(
435             imageversion.getHash()) == imageversion
436
437     def test_negativeGetImageVersionByHash(self):
438         try:
439             self.shelf.getImageVersion(u"badhash")
440         except ImageVersionDoesNotExistError:
441             pass
442         else:
443             assert False
444
445     def test_getImageVersionByLocation(self):
446         imageversion1 = self.shelf.getImageVersionByLocation(
447             os.path.join(PICDIR, u"arlaharen.png"))
448         currentDir = os.getcwd()
449         try:
450             os.chdir(PICDIR)
451             imageversion2 = self.shelf.getImageVersionByLocation(
452                 u"arlaharen.png")
453         finally:
454             os.chdir(currentDir)
455         assert imageversion1 == imageversion2
456
457     def test_negativeGetImageVersionByHash(self):
458         try:
459             self.shelf.getImageVersionByLocation(u"/bad/location")
460         except ImageVersionDoesNotExistError:
461             pass
462         else:
463             assert False
464
465     def test_deleteImage(self):
466         imageversion = self.shelf.getImageVersionByLocation(
467             os.path.join(PICDIR, "arlaharen.png"))
468         imageid = imageversion.getImage().getId()
469         self.shelf.deleteImage(imageid)
470         try:
471             self.shelf.getImageVersionByLocation(
472                 os.path.join(PICDIR, "arlaharen.png"))
473         except ImageVersionDoesNotExistError:
474             pass
475         else:
476             assert False
477
478     def test_negativeImageDeletion(self):
479         try:
480             self.shelf.deleteImage(12345678)
481         except ImageDoesNotExistError:
482             pass
483         else:
484             assert False
485
486     def test_deleteImageVersion(self):
487         imageversion = self.shelf.getImageVersionByLocation(
488             os.path.join(PICDIR, "arlaharen.png"))
489         self.shelf.deleteImageVersion(imageversion.getId())
490
491     def test_negativeImageVersionDeletion(self):
492         try:
493             self.shelf.deleteImageVersion(12345678)
494         except ImageVersionDoesNotExistError:
495             pass
496         else:
497             assert False
498
499     def test_getObject(self):
500         rootalbum = self.shelf.getRootAlbum()
501         album = self.shelf.getObject(rootalbum.getId())
502         assert album == rootalbum
503
504     def test_deleteObject(self):
505         albumid = self.shelf.getAlbumByTag(u"beta").getId()
506         imageversion = self.shelf.getImageVersionByLocation(
507             os.path.join(PICDIR, "arlaharen.png"))
508         imageid = imageversion.getImage().getId()
509         self.shelf.deleteObject(albumid)
510         self.shelf.deleteObject(imageid)
511         try:
512             self.shelf.getAlbum(albumid)
513         except AlbumDoesNotExistError:
514             pass
515         else:
516             assert False
517         try:
518             self.shelf.getImage(imageid)
519         except ImageDoesNotExistError:
520             pass
521         else:
522             assert False
523
524     def test_getAllAttributeNames(self):
525         attrnames = list(self.shelf.getAllAttributeNames())
526         attrnames.sort()
527         assert attrnames == [
528             "cameramake", "cameramodel", "captured", "description",
529             "digitalzoom", "exposurebias", "exposureprogram", "exposuretime",
530             "flash", "fnumber", "focallength", "iso", "orientation", "query",
531             "title"
532             ], attrnames
533
534     def test_getCategory(self):
535         category = self.shelf.getCategory(1)
536         assert category.getId() == 1
537
538     def test_getCategoryByTag(self):
539         category = self.shelf.getCategoryByTag(u"a")
540         assert category.getTag() == u"a"
541
542     def test_negativeCreateCategory(self):
543         try:
544             self.shelf.createCategory(u"a", u"Foo")
545         except CategoryExistsError:
546             pass
547         else:
548             assert False
549
550     def test_deleteCategory(self):
551         category = self.shelf.getCategoryByTag(u"a")
552         self.shelf.deleteCategory(category.getId())
553
554     def test_negativeDeleteCategory(self):
555         try:
556             self.shelf.deleteCategory(12345678)
557         except CategoryDoesNotExistError:
558             pass
559         else:
560             assert False
561
562     def test_getRootCategories(self):
563         categories = list(self.shelf.getRootCategories())
564         cat_a = self.shelf.getCategoryByTag(u"a")
565         cat_events = self.shelf.getCategoryByTag(u"events")
566         cat_locations = self.shelf.getCategoryByTag(u"locations")
567         cat_people = self.shelf.getCategoryByTag(u"people")
568         categories.sort(lambda x, y: cmp(x.getTag(), y.getTag()))
569         assert categories == [cat_a, cat_events, cat_locations, cat_people], \
570                categories
571
572 class TestCategory(TestShelfFixture):
573     def test_categoryMethods(self):
574         cat_a = self.shelf.getCategoryByTag(u"a")
575         cat_b = self.shelf.getCategoryByTag(u"b")
576         cat_c = self.shelf.getCategoryByTag(u"c")
577         cat_d = self.shelf.getCategoryByTag(u"d")
578
579         assert self.shelf.getCategory(cat_a.getId()) == cat_a
580         cat_a.setTag(u"foo")
581         assert self.shelf.getCategoryByTag(u"foo") == cat_a
582
583         assert cat_a.getDescription() == "A"
584         cat_a.setDescription(u"foo")
585         assert cat_a.getDescription() == "foo"
586
587         a_children = list(cat_a.getChildren())
588         a_children.sort(lambda x, y: cmp(x.getId(), y.getId()))
589         assert a_children == [cat_b, cat_c]
590         b_children = list(cat_b.getChildren())
591         assert b_children == [cat_d]
592         d_children = list(cat_d.getChildren())
593         assert d_children == []
594
595         a_parents = list(cat_a.getParents())
596         assert a_parents == []
597         b_parents = list(cat_b.getParents())
598         assert b_parents == [cat_a]
599         d_parents = list(cat_d.getParents())
600         d_parents.sort(lambda x, y: cmp(x.getTag(), y.getTag()))
601         assert d_parents == [cat_b, cat_c]
602
603         assert not cat_a.isChildOf(cat_a)
604         assert cat_b.isChildOf(cat_a)
605         assert cat_c.isChildOf(cat_a)
606         assert not cat_d.isChildOf(cat_a)
607         assert cat_a.isChildOf(cat_a, recursive=True)
608         assert cat_b.isChildOf(cat_a, recursive=True)
609         assert cat_c.isChildOf(cat_a, recursive=True)
610         assert cat_d.isChildOf(cat_a, recursive=True)
611
612         assert not cat_d.isParentOf(cat_d)
613         assert cat_b.isParentOf(cat_d)
614         assert cat_c.isParentOf(cat_d)
615         assert not cat_a.isParentOf(cat_d)
616         assert cat_d.isParentOf(cat_d, recursive=True)
617         assert cat_b.isParentOf(cat_d, recursive=True)
618         assert cat_c.isParentOf(cat_d, recursive=True)
619         assert cat_a.isParentOf(cat_d, recursive=True)
620
621     def test_negativeCategoryConnectChild(self):
622         cat_a = self.shelf.getCategoryByTag(u"a")
623         cat_b = self.shelf.getCategoryByTag(u"b")
624         try:
625             cat_a.connectChild(cat_b)
626         except CategoriesAlreadyConnectedError:
627             pass
628         else:
629             assert False
630         try:
631             cat_b.connectChild(cat_a)
632         except CategoryLoopError:
633             pass
634         else:
635             assert False
636
637     def test_categoryDisconnectChild(self):
638         cat_a = self.shelf.getCategoryByTag(u"a")
639         cat_b = self.shelf.getCategoryByTag(u"b")
640         cat_a.disconnectChild(cat_b)
641         assert not cat_a.isParentOf(cat_b)
642
643     def test_negativeCategoryDisconnectChild(self):
644         cat_a = self.shelf.getCategoryByTag(u"a")
645         cat_d = self.shelf.getCategoryByTag(u"d")
646         cat_a.disconnectChild(cat_d) # No exception.
647
648 class TestObject(TestShelfFixture):
649     def test_getParents(self):
650         root = self.shelf.getRootAlbum()
651         alpha = self.shelf.getAlbumByTag(u"alpha")
652         beta = self.shelf.getAlbumByTag(u"beta")
653         parents = list(beta.getParents())
654         parents.sort(lambda x, y: cmp(x.getTag(), y.getTag()))
655         assert parents == [alpha, root]
656
657     def test_getAttribute(self):
658         orphans = self.shelf.getAlbumByTag(u"orphans")
659         assert orphans.getAttribute(u"title")
660         assert orphans.getAttribute(u"description")
661         orphans.getAttributeMap() # Just populate the cache.
662         assert not orphans.getAttribute(u"nonexisting")
663         assert u"nonexisting" not in orphans.getAttributeMap()
664
665     def test_getAttributeMap(self):
666         orphans = self.shelf.getAlbumByTag(u"orphans")
667         map = orphans.getAttributeMap()
668         assert "description" in map
669         assert "title" in map
670
671     def test_getAttributeNames(self):
672         orphans = self.shelf.getAlbumByTag(u"orphans")
673         names = list(orphans.getAttributeNames())
674         names.sort()
675         assert names == ["description", "title"]
676
677     def test_setAttribute(self):
678         orphans = self.shelf.getAlbumByTag(u"orphans")
679         orphans.setAttribute(u"foo", u"fie") # New.
680         assert orphans.getAttribute(u"foo") == u"fie"
681         assert u"foo" in orphans.getAttributeMap()
682         assert u"foo" in orphans.getAttributeNames()
683         assert orphans.getAttribute(u"title")
684         orphans.setAttribute(u"title", u"gazonk") # Existing
685         assert orphans.getAttribute(u"title") == u"gazonk"
686         assert u"foo" in orphans.getAttributeMap()
687         assert u"foo" in orphans.getAttributeNames()
688
689     def test_deleteAttribute(self):
690         orphans = self.shelf.getAlbumByTag(u"orphans")
691         orphans.deleteAttribute(u"nonexisting") # No exception.
692         assert orphans.getAttribute(u"title")
693         orphans.deleteAttribute(u"title")
694         orphans.getAttributeMap() # Just populate the cache.
695         assert not orphans.getAttribute(u"title")
696         assert u"title" not in orphans.getAttributeMap()
697
698     def test_addCategory(self):
699         orphans = self.shelf.getAlbumByTag(u"orphans")
700         cat_a = self.shelf.getCategoryByTag(u"a")
701         assert list(orphans.getCategories()) == []
702         orphans.addCategory(cat_a)
703         assert list(orphans.getCategories()) == [cat_a]
704         try:
705             orphans.addCategory(cat_a)
706         except CategoryPresentError:
707             pass
708         else:
709             assert False
710         assert list(orphans.getCategories()) == [cat_a]
711
712     def test_removeCategory(self):
713         orphans = self.shelf.getAlbumByTag(u"orphans")
714         assert list(orphans.getCategories()) == []
715         cat_a = self.shelf.getCategoryByTag(u"a")
716         orphans.addCategory(cat_a)
717         assert list(orphans.getCategories()) == [cat_a]
718         orphans.removeCategory(cat_a)
719         assert list(orphans.getCategories()) == []
720
721     def test_deleteCategoryInvalidatesCategoryCache(self):
722         orphans = self.shelf.getAlbumByTag(u"orphans")
723         assert list(orphans.getCategories()) == []
724         cat_a = self.shelf.getCategoryByTag(u"a")
725         orphans.addCategory(cat_a)
726         assert list(orphans.getCategories()) == [cat_a]
727         self.shelf.deleteCategory(cat_a.getId())
728         assert list(orphans.getCategories()) == []
729
730 class TestAlbum(TestShelfFixture):
731     def test_getType(self):
732         alpha = self.shelf.getAlbumByTag(u"alpha")
733         assert alpha.getType() == AlbumType.Plain
734
735     def test_isMutable(self):
736         alpha = self.shelf.getAlbumByTag(u"alpha")
737         assert alpha.isMutable()
738
739     def test_getTag(self):
740         alpha = self.shelf.getAlbumByTag(u"alpha")
741         assert alpha.getTag() == u"alpha"
742
743     def test_setTag(self):
744         alpha = self.shelf.getAlbumByTag(u"alpha")
745         alpha.setTag(u"alfa")
746         assert alpha.getTag() == u"alfa"
747
748     def test_getAlbumParents(self):
749         root = self.shelf.getRootAlbum()
750         alpha = self.shelf.getAlbumByTag(u"alpha")
751         parents = list(alpha.getAlbumParents())
752         parents.sort(lambda x, y: cmp(x.getTag(), y.getTag()))
753         assert parents == [root]
754
755     def test_isAlbum(self):
756         assert self.shelf.getRootAlbum().isAlbum()
757
758 class TestPlainAlbum(TestShelfFixture):
759     def test_getType(self):
760         alpha = self.shelf.getAlbumByTag(u"alpha")
761         assert alpha.getType() == AlbumType.Plain
762
763     def test_isMutable(self):
764         alpha = self.shelf.getAlbumByTag(u"alpha")
765         assert alpha.isMutable()
766
767     def test_getChildren(self):
768         epsilon = self.shelf.getAlbumByTag(u"epsilon")
769         alpha = self.shelf.getAlbumByTag(u"alpha")
770         beta = self.shelf.getAlbumByTag(u"beta")
771         assert list(epsilon.getChildren()) == []
772         alphaChildren = list(alpha.getChildren())
773         assert list(beta.getChildren()) == [alphaChildren[-1]]
774
775     def test_getAlbumChildren(self):
776         alpha = self.shelf.getAlbumByTag(u"alpha")
777         beta = self.shelf.getAlbumByTag(u"beta")
778         epsilon = self.shelf.getAlbumByTag(u"epsilon")
779         alphaAlbumChildren = list(alpha.getAlbumChildren())
780         assert alphaAlbumChildren == [beta]
781         assert list(epsilon.getAlbumChildren()) == []
782
783     def test_setChildren(self):
784         root = self.shelf.getRootAlbum()
785         beta = self.shelf.getAlbumByTag(u"beta")
786         assert list(beta.getChildren()) != []
787         beta.setChildren([beta, root])
788         assert list(beta.getChildren()) == [beta, root]
789         beta.setChildren([]) # Break the cycle.
790         assert list(beta.getChildren()) == []
791
792 class TestImage(TestShelfFixture):
793     def test_isAlbum(self):
794         imageversion = self.shelf.getImageVersionByLocation(
795             os.path.join(PICDIR, "arlaharen.png"))
796         assert not imageversion.getImage().isAlbum()
797
798     def test_getImageVersions(self):
799         imageversion = self.shelf.getImageVersionByLocation(
800             os.path.join(PICDIR, "arlaharen.png"))
801         image = imageversion.getImage()
802         assert list(image.getImageVersions()) == [imageversion]
803         imageversion2 = self.shelf.getImageVersionByLocation(
804             os.path.join(PICDIR, "Canon_Digital_IXUS.jpg"))
805         imageversion2.setImage(image)
806         imageversions = list(image.getImageVersions())
807         imageversions.sort(lambda x, y: cmp(x.getHash(), y.getHash()))
808         assert list(image.getImageVersions()) == [imageversion, imageversion2]
809         self.shelf.deleteImageVersion(imageversion.getId())
810         self.shelf.deleteImageVersion(imageversion2.getId())
811         assert list(image.getImageVersions()) == []
812
813     def test_getPrimaryVersion(self):
814         imageversion = self.shelf.getImageVersionByLocation(
815             os.path.join(PICDIR, "arlaharen.png"))
816         image = imageversion.getImage()
817         assert image.getPrimaryVersion() == imageversion
818         imageversion2 = self.shelf.getImageVersionByLocation(
819             os.path.join(PICDIR, "Canon_Digital_IXUS.jpg"))
820         imageversion2.setImage(image)
821         assert image.getPrimaryVersion() == imageversion
822         imageversion2.makePrimary()
823         assert image.getPrimaryVersion() == imageversion2
824
825         newImage = self.shelf.createImage()
826         lastImageVersion = list(image.getImageVersions())[-1]
827         lastImageVersion.setImage(newImage)
828         assert image.getPrimaryVersion() != lastImageVersion
829         assert newImage.getPrimaryVersion() == lastImageVersion
830         lastImageVersion.setImage(image)
831
832         self.shelf.deleteImageVersion(imageversion2.getId())
833         assert image.getPrimaryVersion() == imageversion
834         self.shelf.deleteImageVersion(imageversion.getId())
835         assert image.getPrimaryVersion() == None
836
837 class TestImageVersion(TestShelfFixture):
838     def test_getType(self):
839         imageversion = self.shelf.getImageVersionByLocation(
840             os.path.join(PICDIR, "arlaharen.png"))
841         assert imageversion.getType() == ImageVersionType.Original
842         imageversion.setType(ImageVersionType.Important)
843         assert imageversion.getType() == ImageVersionType.Important
844         imageversion.setType(ImageVersionType.Other)
845         assert imageversion.getType() == ImageVersionType.Other
846         imageversion.setType(ImageVersionType.Original)
847         assert imageversion.getType() == ImageVersionType.Original
848
849     # ImageVersion.makePrimary tested in TestImage.test_getPrimaryVersion.
850     # ImageVersion.setImage tested in TestImage.test_getPrimaryVersion.
851     # ImageVersion.setType tested in TestImageVersion.test_getType.
852     # ImageVersion.setComment tested in TestImageVersion.test_getComment.
853
854     def test_getComment(self):
855         imageversion = self.shelf.getImageVersionByLocation(
856             os.path.join(PICDIR, "arlaharen.png"))
857         assert imageversion.getComment() == ""
858         imageversion.setComment(u"a comment")
859         assert imageversion.getComment() == u"a comment"
860
861     def test_getHash(self):
862         imageversion = self.shelf.getImageVersionByLocation(
863             os.path.join(PICDIR, "arlaharen.png"))
864         assert imageversion.getHash() == "39a1266d2689f53d48b09a5e0ca0af1f"
865
866     def test_getLocation(self):
867         location = os.path.join(PICDIR, "arlaharen.png")
868         imageversion = self.shelf.getImageVersionByLocation(location)
869         assert imageversion.getLocation() == os.path.realpath(location)
870
871     def test_getModificationTime(self):
872         imageversion = self.shelf.getImageVersionByLocation(
873             os.path.join(PICDIR, "arlaharen.png"))
874         t = imageversion.getModificationTime()
875         assert isinstance(t, int)
876         assert t > 0
877
878     def test_getSize(self):
879         imageversion = self.shelf.getImageVersionByLocation(
880             os.path.join(PICDIR, "arlaharen.png"))
881         assert imageversion.getSize() == (304, 540)
882
883     def test_contentChanged(self):
884         path = os.path.join(PICDIR, "arlaharen.png")
885         imageversion = self.shelf.getImageVersionByLocation(path)
886         self.shelf.deleteImageVersion(imageversion.getId())
887         newpath = u"tmp.png"
888         try:
889             shutil.copy2(path, newpath)
890             newimage = self.shelf.createImage()
891             newimageversion = self.shelf.createImageVersion(
892                 newimage, newpath, ImageVersionType.Original)
893             oldmtime = imageversion.getModificationTime()
894             pilimg = PILImage.open(newpath)
895             pilimg.thumbnail((100, 100))
896             pilimg.save(newpath, "PNG")
897             newimageversion.contentChanged()
898             assert newimageversion.getHash() == "d55a9cc74371c09d484b163c71497cab"
899             assert newimageversion.getSize() == (56, 100)
900             assert newimageversion.getModificationTime() > oldmtime
901         finally:
902             try:
903                 os.unlink(newpath)
904             except OSError:
905                 pass
906
907     def test_locationChanged(self):
908         location = os.path.join(PICDIR, "arlaharen.png")
909         imageversion = self.shelf.getImageVersionByLocation(location)
910         imageversion.locationChanged(u"/foo/../bar")
911         assert imageversion.getLocation() == "/bar"
912
913     def test_importExifTags(self):
914         imageversion = self.shelf.getImageVersionByLocation(
915             os.path.join(PICDIR, "arlaharen.png"))
916         imageversion.importExifTags(True) # TODO: Test more.
917         imageversion.importExifTags(False) # TODO: Test more.
918
919 class TestOrphansAlbum(TestShelfFixture):
920     def test_getType(self):
921         orphans = self.shelf.getAlbumByTag(u"orphans")
922         assert orphans.getType() == AlbumType.Orphans
923
924     def test_isMutable(self):
925         orphans = self.shelf.getAlbumByTag(u"orphans")
926         assert not orphans.isMutable()
927
928     def test_getChildren(self):
929         orphans = self.shelf.getAlbumByTag(u"orphans")
930         assert len(list(orphans.getChildren())) == 2
931
932     def test_getAlbumChildren(self):
933         orphans = self.shelf.getAlbumByTag(u"orphans")
934         epsilon = self.shelf.getAlbumByTag(u"epsilon")
935         assert list(orphans.getAlbumChildren()) == [epsilon]
936
937     def test_setChildren(self):
938         orphans = self.shelf.getAlbumByTag(u"orphans")
939         try:
940             orphans.setChildren([])
941         except UnsettableChildrenError:
942             pass
943         else:
944             assert False
945
946     def test_isAlbum(self):
947         assert self.shelf.getAlbumByTag(u"orphans").isAlbum()
948
949 class TestSearchAlbum(TestShelfFixture):
950     def test_getType(self):
951         zeta = self.shelf.getAlbumByTag(u"zeta")
952         assert zeta.getType() == AlbumType.Search
953
954     def test_isMutable(self):
955         zeta = self.shelf.getAlbumByTag(u"zeta")
956         assert not zeta.isMutable()
957
958     def test_getChildren(self):
959         alpha = self.shelf.getAlbumByTag(u"alpha")
960         image1, image2 = list(alpha.getChildren())[0:2]
961         cat_a = self.shelf.getCategoryByTag(u"a")
962         cat_b = self.shelf.getCategoryByTag(u"b")
963         image1.addCategory(cat_a)
964         image2.addCategory(cat_b)
965         zeta = self.shelf.getAlbumByTag(u"zeta")
966         assert zeta
967         zeta.setAttribute(u"query", u"b")
968         children = zeta.getChildren()
969         assert list(children) == [image2]
970
971     def test_getAlbumChildren(self):
972         alpha = self.shelf.getAlbumByTag(u"alpha")
973         image1, image2 = list(alpha.getChildren())[0:2]
974         cat_a = self.shelf.getCategoryByTag(u"a")
975         cat_b = self.shelf.getCategoryByTag(u"b")
976         image1.addCategory(cat_a)
977         image2.addCategory(cat_b)
978         zeta = self.shelf.getAlbumByTag(u"zeta")
979         assert zeta
980         zeta.setAttribute(u"query", u"b")
981         children = zeta.getAlbumChildren()
982         l = list(children)
983         assert list(children) == []
984
985     def test_setChildren(self):
986         zeta = self.shelf.getAlbumByTag(u"zeta")
987         try:
988             zeta.setChildren([])
989         except UnsettableChildrenError:
990             pass
991         else:
992             assert False
993
994     def test_isAlbum(self):
995         assert self.shelf.getAlbumByTag(u"zeta").isAlbum()
996
997 ######################################################################
998
999 removeTmpDb()
1000 if __name__ == "__main__":
1001     unittest.main()