mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-11-24 23:35:01 -05:00
346 lines
15 KiB
Python
346 lines
15 KiB
Python
#!/usr/bin/env python
|
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
from __future__ import (unicode_literals, division, absolute_import,
|
|
print_function)
|
|
|
|
__license__ = 'GPL v3'
|
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
__docformat__ = 'restructuredtext en'
|
|
|
|
import datetime
|
|
from io import BytesIO
|
|
|
|
from calibre.utils.date import utc_tz
|
|
from calibre.db.tests.base import BaseTest
|
|
|
|
class ReadingTest(BaseTest):
|
|
|
|
def test_read(self): # {{{
|
|
'Test the reading of data from the database'
|
|
cache = self.init_cache(self.library_path)
|
|
tests = {
|
|
3 : {
|
|
'title': 'Unknown',
|
|
'sort': 'Unknown',
|
|
'authors': ('Unknown',),
|
|
'author_sort': 'Unknown',
|
|
'series' : None,
|
|
'series_index': 1.0,
|
|
'rating': None,
|
|
'tags': (),
|
|
'formats':(),
|
|
'identifiers': {},
|
|
'timestamp': datetime.datetime(2011, 9, 7, 19, 54, 41,
|
|
tzinfo=utc_tz),
|
|
'pubdate': datetime.datetime(2011, 9, 7, 19, 54, 41,
|
|
tzinfo=utc_tz),
|
|
'last_modified': datetime.datetime(2011, 9, 7, 19, 54, 41,
|
|
tzinfo=utc_tz),
|
|
'publisher': None,
|
|
'languages': (),
|
|
'comments': None,
|
|
'#enum': None,
|
|
'#authors':(),
|
|
'#date':None,
|
|
'#rating':None,
|
|
'#series':None,
|
|
'#series_index': None,
|
|
'#tags':(),
|
|
'#yesno':None,
|
|
'#comments': None,
|
|
'size':None,
|
|
},
|
|
|
|
2 : {
|
|
'title': 'Title One',
|
|
'sort': 'One',
|
|
'authors': ('Author One',),
|
|
'author_sort': 'One, Author',
|
|
'series' : 'A Series One',
|
|
'series_index': 1.0,
|
|
'tags':('Tag One', 'Tag Two'),
|
|
'formats': ('FMT1',),
|
|
'rating': 4.0,
|
|
'identifiers': {'test':'one'},
|
|
'timestamp': datetime.datetime(2011, 9, 5, 21, 6,
|
|
tzinfo=utc_tz),
|
|
'pubdate': datetime.datetime(2011, 9, 5, 21, 6,
|
|
tzinfo=utc_tz),
|
|
'publisher': 'Publisher One',
|
|
'languages': ('eng',),
|
|
'comments': '<p>Comments One</p>',
|
|
'#enum':'One',
|
|
'#authors':('Custom One', 'Custom Two'),
|
|
'#date':datetime.datetime(2011, 9, 5, 6, 0,
|
|
tzinfo=utc_tz),
|
|
'#rating':2.0,
|
|
'#series':'My Series One',
|
|
'#series_index': 1.0,
|
|
'#tags':('My Tag One', 'My Tag Two'),
|
|
'#yesno':True,
|
|
'#comments': '<div>My Comments One<p></p></div>',
|
|
'size':9,
|
|
},
|
|
1 : {
|
|
'title': 'Title Two',
|
|
'sort': 'Title Two',
|
|
'authors': ('Author Two', 'Author One'),
|
|
'author_sort': 'Two, Author & One, Author',
|
|
'series' : 'A Series One',
|
|
'series_index': 2.0,
|
|
'rating': 6.0,
|
|
'tags': ('Tag One', 'News'),
|
|
'formats':('FMT1', 'FMT2'),
|
|
'identifiers': {'test':'two'},
|
|
'timestamp': datetime.datetime(2011, 9, 6, 6, 0,
|
|
tzinfo=utc_tz),
|
|
'pubdate': datetime.datetime(2011, 8, 5, 6, 0,
|
|
tzinfo=utc_tz),
|
|
'publisher': 'Publisher Two',
|
|
'languages': ('deu',),
|
|
'comments': '<p>Comments Two</p>',
|
|
'#enum':'Two',
|
|
'#authors':('My Author Two',),
|
|
'#date':datetime.datetime(2011, 9, 1, 6, 0,
|
|
tzinfo=utc_tz),
|
|
'#rating':4.0,
|
|
'#series':'My Series Two',
|
|
'#series_index': 3.0,
|
|
'#tags':('My Tag Two',),
|
|
'#yesno':False,
|
|
'#comments': '<div>My Comments Two<p></p></div>',
|
|
'size':9,
|
|
|
|
},
|
|
}
|
|
for book_id, test in tests.iteritems():
|
|
for field, expected_val in test.iteritems():
|
|
val = cache.field_for(field, book_id)
|
|
if isinstance(val, tuple) and 'authors' not in field and 'languages' not in field:
|
|
val, expected_val = set(val), set(expected_val)
|
|
self.assertEqual(expected_val, val,
|
|
'Book id: %d Field: %s failed: %r != %r'%(
|
|
book_id, field, expected_val, val))
|
|
# }}}
|
|
|
|
def test_sorting(self): # {{{
|
|
'Test sorting'
|
|
cache = self.init_cache(self.library_path)
|
|
for field, order in {
|
|
'title' : [2, 1, 3],
|
|
'authors': [2, 1, 3],
|
|
'series' : [3, 1, 2],
|
|
'tags' : [3, 1, 2],
|
|
'rating' : [3, 2, 1],
|
|
# 'identifiers': [3, 2, 1], There is no stable sort since 1 and
|
|
# 2 have the same identifier keys
|
|
# 'last_modified': [3, 2, 1], There is no stable sort as two
|
|
# records have the exact same value
|
|
'timestamp': [2, 1, 3],
|
|
'pubdate' : [1, 2, 3],
|
|
'publisher': [3, 2, 1],
|
|
'languages': [3, 2, 1],
|
|
'comments': [3, 2, 1],
|
|
'#enum' : [3, 2, 1],
|
|
'#authors' : [3, 2, 1],
|
|
'#date': [3, 1, 2],
|
|
'#rating':[3, 2, 1],
|
|
'#series':[3, 2, 1],
|
|
'#tags':[3, 2, 1],
|
|
'#yesno':[3, 1, 2],
|
|
'#comments':[3, 2, 1],
|
|
# TODO: Add an empty book to the db and ensure that empty
|
|
# fields sort the same as they do in db2
|
|
}.iteritems():
|
|
x = list(reversed(order))
|
|
self.assertEqual(order, cache.multisort([(field, True)],
|
|
ids_to_sort=x),
|
|
'Ascending sort of %s failed'%field)
|
|
self.assertEqual(x, cache.multisort([(field, False)],
|
|
ids_to_sort=order),
|
|
'Descending sort of %s failed'%field)
|
|
|
|
# Test subsorting
|
|
self.assertEqual([3, 2, 1], cache.multisort([('identifiers', True),
|
|
('title', True)]), 'Subsort failed')
|
|
# }}}
|
|
|
|
def test_get_metadata(self): # {{{
|
|
'Test get_metadata() returns the same data for both backends'
|
|
from calibre.library.database2 import LibraryDatabase2
|
|
old = LibraryDatabase2(self.library_path)
|
|
old_metadata = {i:old.get_metadata(
|
|
i, index_is_id=True, get_cover=True, cover_as_data=True) for i in
|
|
xrange(1, 4)}
|
|
for mi in old_metadata.itervalues():
|
|
mi.format_metadata = dict(mi.format_metadata)
|
|
if mi.formats:
|
|
mi.formats = tuple(mi.formats)
|
|
old.conn.close()
|
|
old = None
|
|
|
|
cache = self.init_cache(self.library_path)
|
|
|
|
new_metadata = {i:cache.get_metadata(
|
|
i, get_cover=True, cover_as_data=True) for i in xrange(1, 4)}
|
|
cache = None
|
|
for mi2, mi1 in zip(new_metadata.values(), old_metadata.values()):
|
|
self.compare_metadata(mi1, mi2)
|
|
# }}}
|
|
|
|
def test_get_cover(self): # {{{
|
|
'Test cover() returns the same data for both backends'
|
|
from calibre.library.database2 import LibraryDatabase2
|
|
old = LibraryDatabase2(self.library_path)
|
|
covers = {i: old.cover(i, index_is_id=True) for i in old.all_ids()}
|
|
old.conn.close()
|
|
old = None
|
|
cache = self.init_cache(self.library_path)
|
|
for book_id, cdata in covers.iteritems():
|
|
self.assertEqual(cdata, cache.cover(book_id), 'Reading of cover failed')
|
|
f = cache.cover(book_id, as_file=True)
|
|
self.assertEqual(cdata, f.read() if f else f, 'Reading of cover as file failed')
|
|
if cdata:
|
|
with open(cache.cover(book_id, as_path=True), 'rb') as f:
|
|
self.assertEqual(cdata, f.read(), 'Reading of cover as path failed')
|
|
else:
|
|
self.assertEqual(cdata, cache.cover(book_id, as_path=True),
|
|
'Reading of null cover as path failed')
|
|
buf = BytesIO()
|
|
self.assertFalse(cache.copy_cover_to(99999, buf), 'copy_cover_to() did not return False for non-existent book_id')
|
|
self.assertFalse(cache.copy_cover_to(3, buf), 'copy_cover_to() did not return False for non-existent cover')
|
|
|
|
# }}}
|
|
|
|
def test_searching(self): # {{{
|
|
'Test searching returns the same data for both backends'
|
|
from calibre.library.database2 import LibraryDatabase2
|
|
old = LibraryDatabase2(self.library_path)
|
|
oldvals = {query:set(old.search_getting_ids(query, '')) for query in (
|
|
# Date tests
|
|
'date:9/6/2011', 'date:true', 'date:false', 'pubdate:9/2011',
|
|
'#date:true', 'date:<100daysago', 'date:>9/6/2011',
|
|
'#date:>9/1/2011', '#date:=2011',
|
|
|
|
# Number tests
|
|
'rating:3', 'rating:>2', 'rating:=2', 'rating:true',
|
|
'rating:false', 'rating:>4', 'tags:#<2', 'tags:#>7',
|
|
'cover:false', 'cover:true', '#float:>11', '#float:<1k',
|
|
'#float:10.01', 'series_index:1', 'series_index:<3', 'id:1',
|
|
'id:>2',
|
|
|
|
# Bool tests
|
|
'#yesno:true', '#yesno:false', '#yesno:yes', '#yesno:no',
|
|
'#yesno:empty',
|
|
|
|
# Keypair tests
|
|
'identifiers:true', 'identifiers:false', 'identifiers:test',
|
|
'identifiers:test:false', 'identifiers:test:one',
|
|
'identifiers:t:n', 'identifiers:=test:=two', 'identifiers:x:y',
|
|
'identifiers:z',
|
|
|
|
# Text tests
|
|
'title:="Title One"', 'title:~title', '#enum:=one', '#enum:tw',
|
|
'#enum:false', '#enum:true', 'series:one', 'tags:one', 'tags:true',
|
|
'tags:false', '2', 'one', '20.02', '"publisher one"',
|
|
'"my comments one"',
|
|
|
|
# User categories
|
|
'@Good Authors:One', '@Good Series.good tags:two',
|
|
|
|
# Cover/Formats
|
|
'cover:true', 'cover:false', 'formats:true', 'formats:false',
|
|
'formats:#>1', 'formats:#=1', 'formats:=fmt1', 'formats:=fmt2',
|
|
'formats:=fmt1 or formats:fmt2', '#formats:true', '#formats:false',
|
|
'#formats:fmt1', '#formats:fmt2', '#formats:fmt1 and #formats:fmt2',
|
|
|
|
)}
|
|
old.conn.close()
|
|
old = None
|
|
|
|
cache = self.init_cache(self.library_path)
|
|
for query, ans in oldvals.iteritems():
|
|
nr = cache.search(query, '')
|
|
self.assertEqual(ans, nr,
|
|
'Old result: %r != New result: %r for search: %s'%(
|
|
ans, nr, query))
|
|
|
|
# }}}
|
|
|
|
def test_get_categories(self): # {{{
|
|
'Check that get_categories() returns the same data for both backends'
|
|
from calibre.library.database2 import LibraryDatabase2
|
|
old = LibraryDatabase2(self.library_path)
|
|
old_categories = old.get_categories()
|
|
old.conn.close()
|
|
cache = self.init_cache(self.library_path)
|
|
new_categories = cache.get_categories()
|
|
self.assertEqual(set(old_categories), set(new_categories),
|
|
'The set of old categories is not the same as the set of new categories')
|
|
|
|
def compare_category(category, old, new):
|
|
for attr in ('name', 'original_name', 'id', 'count',
|
|
'is_hierarchical', 'is_editable', 'is_searchable',
|
|
'id_set', 'avg_rating', 'sort', 'use_sort_as_name',
|
|
'tooltip', 'icon', 'category'):
|
|
oval, nval = getattr(old, attr), getattr(new, attr)
|
|
if (
|
|
(category in {'rating', '#rating'} and attr in {'id_set', 'sort'}) or
|
|
(category == 'series' and attr == 'sort') or # Sorting is wrong in old
|
|
(category == 'identifiers' and attr == 'id_set') or
|
|
(category == '@Good Series') or # Sorting is wrong in old
|
|
(category == 'news' and attr in {'count', 'id_set'}) or
|
|
(category == 'formats' and attr == 'id_set')
|
|
):
|
|
continue
|
|
self.assertEqual(oval, nval,
|
|
'The attribute %s for %s in category %s does not match. Old is %r, New is %r'
|
|
%(attr, old.name, category, oval, nval))
|
|
|
|
for category in old_categories:
|
|
old, new = old_categories[category], new_categories[category]
|
|
self.assertEqual(len(old), len(new),
|
|
'The number of items in the category %s is not the same'%category)
|
|
for o, n in zip(old, new):
|
|
compare_category(category, o, n)
|
|
|
|
# }}}
|
|
|
|
def test_get_formats(self): # {{{
|
|
'Test reading ebook formats using the format() method'
|
|
from calibre.library.database2 import LibraryDatabase2
|
|
from calibre.db.cache import NoSuchFormat
|
|
old = LibraryDatabase2(self.library_path)
|
|
ids = old.all_ids()
|
|
lf = {i:set(old.formats(i, index_is_id=True).split(',')) if old.formats(
|
|
i, index_is_id=True) else set() for i in ids}
|
|
formats = {i:{f:old.format(i, f, index_is_id=True) for f in fmts} for
|
|
i, fmts in lf.iteritems()}
|
|
old.conn.close()
|
|
old = None
|
|
cache = self.init_cache(self.library_path)
|
|
for book_id, fmts in lf.iteritems():
|
|
self.assertEqual(fmts, set(cache.formats(book_id)),
|
|
'Set of formats is not the same')
|
|
for fmt in fmts:
|
|
old = formats[book_id][fmt]
|
|
self.assertEqual(old, cache.format(book_id, fmt),
|
|
'Old and new format disagree')
|
|
f = cache.format(book_id, fmt, as_file=True)
|
|
self.assertEqual(old, f.read(),
|
|
'Failed to read format as file')
|
|
with open(cache.format(book_id, fmt, as_path=True,
|
|
preserve_filename=True), 'rb') as f:
|
|
self.assertEqual(old, f.read(),
|
|
'Failed to read format as path')
|
|
with open(cache.format(book_id, fmt, as_path=True), 'rb') as f:
|
|
self.assertEqual(old, f.read(),
|
|
'Failed to read format as path')
|
|
|
|
buf = BytesIO()
|
|
self.assertRaises(NoSuchFormat, cache.copy_format_to, 99999, 'X', buf, 'copy_format_to() failed to raise an exception for non-existent book')
|
|
self.assertRaises(NoSuchFormat, cache.copy_format_to, 1, 'X', buf, 'copy_format_to() failed to raise an exception for non-existent format')
|
|
|
|
# }}}
|
|
|