%PDF- %PDF-
| Direktori : /usr/lib/calibre/calibre/ebooks/oeb/polish/tests/ |
| Current File : //usr/lib/calibre/calibre/ebooks/oeb/polish/tests/container.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import os, subprocess
from zipfile import ZipFile
from calibre import CurrentDir
from calibre.ebooks.oeb.polish.tests.base import BaseTest, get_simple_book, get_split_book
from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_container, OCF_NS
from calibre.ebooks.oeb.polish.replace import rename_files, rationalize_folders
from calibre.ebooks.oeb.polish.split import split, merge
from calibre.utils.filenames import nlinks_file
from calibre.ptempfile import TemporaryFile, TemporaryDirectory
from polyglot.builtins import iteritems, itervalues
def get_container(*args, **kwargs):
kwargs['tweak_mode'] = True
return _gc(*args, **kwargs)
class ContainerTests(BaseTest):
def test_clone(self):
' Test cloning of containers '
for fmt in ('epub', 'azw3'):
base = os.path.join(self.tdir, fmt + '-')
book = get_simple_book(fmt)
tdir = base + 'first'
os.mkdir(tdir)
c1 = get_container(book, tdir=tdir)
tdir = base + 'second'
os.mkdir(tdir)
c2 = clone_container(c1, tdir)
for c in (c1, c2):
for name, path in iteritems(c.name_path_map):
self.assertEqual(2, nlinks_file(path), 'The file %s is not linked' % name)
for name in c1.name_path_map:
self.assertIn(name, c2.name_path_map)
self.assertEqual(c1.open(name).read(), c2.open(name).read(), 'The file %s differs' % name)
spine_names = tuple(x[0] for x in c1.spine_names)
text = spine_names[0]
root = c2.parsed(text)
root.xpath('//*[local-name()="body"]')[0].set('id', 'changed id for test')
c2.dirty(text)
c2.commit_item(text)
for c in (c1, c2):
self.assertEqual(1, nlinks_file(c.name_path_map[text]))
self.assertNotEqual(c1.open(text).read(), c2.open(text).read())
name = spine_names[1]
with c1.open(name, mode='r+b') as f:
f.seek(0, 2)
f.write(b' ')
for c in (c1, c2):
self.assertEqual(1, nlinks_file(c.name_path_map[name]))
self.assertNotEqual(c1.open(name).read(), c2.open(name).read())
x = base + 'out.' + fmt
for c in (c1, c2):
c.commit(outpath=x)
def test_file_removal(self):
' Test removal of files from the container '
book = get_simple_book()
c = get_container(book, tdir=self.tdir)
files = ('toc.ncx', 'cover.png', 'titlepage.xhtml')
self.assertIn('titlepage.xhtml', {x[0] for x in c.spine_names})
self.assertTrue(c.opf_xpath('//opf:meta[@name="cover"]'))
for x in files:
c.remove_item(x)
self.assertIn(c.opf_name, c.dirtied)
self.assertNotIn('titlepage.xhtml', {x[0] for x in c.spine_names})
self.assertFalse(c.opf_xpath('//opf:meta[@name="cover"]'))
raw = c.serialize_item(c.opf_name).decode('utf-8')
for x in files:
self.assertNotIn(x, raw)
def run_external_tools(self, container, vim=False, epubcheck=True):
with TemporaryFile(suffix='.epub', dir=self.tdir) as f:
container.commit(outpath=f)
if vim:
subprocess.Popen(['vim', '-f', f]).wait()
if epubcheck:
subprocess.Popen(['epubcheck', f]).wait()
def test_file_rename(self):
' Test renaming of files '
book = get_simple_book()
count = [0]
def new_container():
count[0] += 1
tdir = os.mkdir(os.path.join(self.tdir, str(count[0])))
return get_container(book, tdir=tdir)
# Test simple opf rename
c = new_container()
orig_name = c.opf_name
name = 'renamed opf.opf'
rename_files(c, {c.opf_name: name})
self.assertEqual(c.opf_name, name)
for x in ('name_path_map', 'mime_map'):
self.assertNotIn(orig_name, getattr(c, x))
self.assertIn(name, getattr(c, x))
self.assertNotIn(name, c.dirtied)
root = c.parsed('META-INF/container.xml')
vals = set(root.xpath(
r'child::ocf:rootfiles/ocf:rootfile/@full-path',
namespaces={'ocf':OCF_NS}))
self.assertSetEqual(vals, {name})
self.check_links(c)
# Test a rename that moves the OPF into different directory
c = new_container()
orig_name = c.opf_name
name = 'renamed/again/metadata.opf'
rename_files(c, {c.opf_name: name})
self.check_links(c)
# Test that renaming commits dirtied items
c = new_container()
name = next(c.spine_names)[0]
root = c.parsed(name)
root.xpath('//*[local-name()="body"]')[0].set('id', 'rename-dirty-test')
rename_files(c, {name:'other/' + name})
with c.open('other/' + name) as f:
raw = f.read()
self.assertIn(b'id="rename-dirty-test"', raw)
self.check_links(c)
# Test renaming of stylesheets
c = new_container()
rename_files(c, {'stylesheet.css':'styles/s 1.css', 'page_styles.css':'styles/p 1.css'})
self.check_links(c)
# Test renaming of images
c = new_container()
rename_files(c, {'cover.png':'images/cover img.png', 'light_wood.png':'images/light wood.png', 'marked.png':'images/marked img.png'})
self.check_links(c)
# Test renaming of ToC
c = new_container()
rename_files(c, {'toc.ncx': 'toc/toc file.ncx'})
self.check_links(c)
# Test renaming of font files
c = new_container()
fname = 'LiberationMono-Regular.ttf'
if fname not in c.name_path_map:
fname = fname.lower() # On OS X the font file name is lowercased for some reason (maybe on windows too)
rename_files(c, {fname: 'fonts/LiberationMono Regular.ttf'})
self.check_links(c)
# Test renaming of text files
c = new_container()
rename_files(c, {'index_split_000.html':'text/page one fällen.html', 'index_split_001.html':'text/page two fällen.html'})
self.check_links(c)
# Test rename with only case change
c = new_container()
rename_files(c, {'index_split_000.html':'Index_split_000.html'})
self.check_links(c)
# self.run_external_tools(c, vim=True)
def test_file_add(self):
' Test adding of files '
book = get_simple_book()
c = get_container(book)
name = 'folder/added file.html'
c.add_file(name, b'xxx')
self.assertEqual('xxx', c.raw_data(name))
self.assertIn(name, set(itervalues(c.manifest_id_map)))
self.assertIn(name, {x[0] for x in c.spine_names})
name = 'added.css'
c.add_file(name, b'xxx')
self.assertEqual('xxx', c.raw_data(name))
self.assertIn(name, set(itervalues(c.manifest_id_map)))
self.assertNotIn(name, {x[0] for x in c.spine_names})
self.assertEqual(c.make_name_unique(name), 'added-1.css')
c.add_file('added-1.css', b'xxx')
self.assertEqual(c.make_name_unique(name.upper()), 'added-2.css'.upper())
self.check_links(c)
def test_actual_case(self):
' Test getting the actual case for files from names on case insensitive filesystems '
from calibre.ebooks.oeb.polish.utils import actual_case_for_name, corrected_case_for_name
book = get_simple_book()
c = get_container(book)
name = 'f1/f2/added file.html'
c.add_file(name, b'xxx')
self.assertTrue(c.exists(name))
variations = (name, name.upper(), name.replace('f1', 'F1'), name.replace('f2', 'F2'))
if c.exists(name.upper()):
for n in variations:
self.assertEqual(name, actual_case_for_name(c, n))
else:
for n in variations:
self.assertEqual(name, corrected_case_for_name(c, n))
self.assertIsNone(corrected_case_for_name(c, name+'/xx'))
def test_split_file(self):
' Test splitting of files '
book = get_split_book()
c = get_container(book)
name = 'index.html'
nname = split(c, name, '//*[@id="page2"]')
root = c.parsed(nname)
troot = c.parsed(name)
self.assertEqual(1, len(root.xpath('//*[@id="container"]')), 'Split point was not adjusted')
self.assertEqual(0, len(troot.xpath('//*[@id="container"]')), 'Split point was not adjusted')
self.check_links(c)
def test_merge_file(self):
' Test merging of files '
book = get_simple_book()
c = get_container(book)
merge(c, 'text', ('index_split_000.html', 'index_split_001.html'), 'index_split_000.html')
self.check_links(c)
book = get_simple_book()
c = get_container(book)
one, two = 'one/one.html', 'two/two.html'
c.add_file(one, b'<head><link href="../stylesheet.css"><p><a name="one" href="../two/two.html">1</a><a name="two" href="../two/two.html#one">2</a>') # noqa
c.add_file(two, b'<head><link href="../page_styles.css"><p><a name="one" href="two.html#two">1</a><a name="two" href="../one/one.html#one">2</a><a href="#one">3</a>') # noqa
merge(c, 'text', (one, two), one)
self.check_links(c)
root = c.parsed(one)
self.assertEqual(1, len(root.xpath('//*[@href="../page_styles.css"]')))
book = get_simple_book()
c = get_container(book)
merge(c, 'styles', ('stylesheet.css', 'page_styles.css'), 'stylesheet.css')
self.check_links(c)
def test_dir_container(self):
def create_book(source):
with ZipFile(P('quick_start/eng.epub', allow_user_override=False)) as zf:
zf.extractall(source)
with CurrentDir(source):
self.assertTrue(os.path.exists('images/cover.jpg'))
with open('.gitignore', 'wb') as f:
f.write(b'nothing')
os.mkdir('.git')
with open('.git/xxx', 'wb') as f:
f.write(b'xxx')
with TemporaryDirectory('-polish-dir-container') as source:
create_book(source)
c = get_container(source)
c.remove_item('images/cover.jpg')
with c.open('images/test-container.xyz', 'wb') as f:
f.write(b'xyz')
c.commit()
with CurrentDir(source):
self.assertTrue(os.path.exists('.gitignore'))
self.assertTrue(os.path.exists('.git/xxx'))
self.assertTrue(os.path.exists('images/test-container.xyz'))
self.assertFalse(os.path.exists('images/cover.jpg'))
def test_folder_type_map_case(self):
book = get_simple_book()
c = get_container(book)
c.add_file('Image/testcase.png', b'xxx')
rationalize_folders(c, {'image':'image'})
self.assertTrue(c.has_name('Image/testcase.png'))
self.assertTrue(c.exists('Image/testcase.png'))
self.assertFalse(c.has_name('image/testcase.png'))